feat: 对账升级

master
zhangtao 4 years ago
commit e4dd28bc0d

@ -164,7 +164,7 @@ public class PlatformClearAnalysisServiceImpl implements PlatformClearService {
@Transactional @Transactional
public void doVerifyAlipaySettleLog(Date dateStr) throws Exception { public void doVerifyAlipaySettleLog(Date dateStr) throws Exception {
JSONObject aliSettleLog = alipayClient.downloadRetailSettlements(dateStr); JSONObject aliSettleLog = alipayClient.oldDownloadRetailSettlements(dateStr);
saveAlipaySettleLog(dateStr, aliSettleLog, "Alipay"); saveAlipaySettleLog(dateStr, aliSettleLog, "Alipay");
} }

@ -0,0 +1,123 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile;
import au.com.royalpay.payment.core.ChannelBillValidator;
import au.com.royalpay.payment.core.beans.ChannelBillPackage;
import au.com.royalpay.payment.core.exceptions.ChannelNotSupportedException;
import au.com.royalpay.payment.tools.defines.PayChannel;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Component;
import org.thymeleaf.util.ListUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @Description
* @title:
* @Date 2020/11/5 15:06
* @author: zhangTao
*/
@Component
public class ChannelReconciliationFile {
private ChannelReconciliationFileTunnel tunnel;
private final Map<PayChannel, ChannelBillValidator> validatorMap ;
public ChannelReconciliationFile(ChannelReconciliationFileTunnel tunnel ,ChannelBillValidator[] validators) {
this.tunnel = tunnel;
validatorMap = Arrays.stream(validators).collect(Collectors.toMap(ChannelBillValidator::payChannel,channelBillValidator -> channelBillValidator));
}
public PageList<ChannelReconciliationFileDTO> list(ChannelReconciliationFileQueryParameter channelReconciliationFileQueryParameter) {
return this.tunnel.list(channelReconciliationFileQueryParameter);
}
public ChannelReconciliationFileContent download(ChannelReconciliationFileDownloadParameter from) {
Optional<Map.Entry<PayChannel, ChannelBillValidator>> channel = findChannels(from.getChannel());
if (!channel.isPresent()) {
throw new ChannelNotSupportedException();
}
Map.Entry<PayChannel, ChannelBillValidator> channelChannelBillValidatorEntry = channel.get();
ChannelBillValidator channelBillValidator = channelChannelBillValidatorEntry.getValue();
List<ChannelBillPackage> channelBillPackageList = selectTypeDown(from ,channelBillValidator);
if (isNull(channelBillPackageList)) {
throw new ChannelReconciliationFileEmptyException();
}
if (isMultiFile(channelBillPackageList)) {
return genMultiFile(channelBillPackageList);
}
return genSingleFile(channelBillPackageList.get(0));
}
private List<ChannelBillPackage> selectTypeDown(ChannelReconciliationFileDownloadParameter from, ChannelBillValidator channelBillValidator) {
if (from.billType().equals("SETTLEMENT")){
return channelBillValidator
.downloadRawSettlementFiles(from.pid(), from.billDate(), from.isUseCash());
}
return channelBillValidator.downloadRawTransactionFiles(from.pid(), from.billDate(), from.isUseCash());
}
private boolean isMultiFile(List<ChannelBillPackage> channelBillPackageList) {
return channelBillPackageList.size() > 1;
}
private boolean isNull(List<ChannelBillPackage> channelBillPackageList){
return ListUtils.isEmpty(channelBillPackageList);
}
private ChannelReconciliationFileContent genSingleFile(ChannelBillPackage channelBillPackage) {
return ChannelReconciliationFileContent.instance(channelBillPackage.getFilename(),
channelBillPackage.getBillContent());
}
private ChannelReconciliationFileContent genMultiFile(List<ChannelBillPackage> channelBillPackageList) {
try (ByteArrayOutputStream stream = new ByteArrayOutputStream(); ZipOutputStream zipOutputStream = new ZipOutputStream(stream)) {
channelBillPackageList.forEach(bill -> toZipOutputStream(bill, zipOutputStream));
zipOutputStream.close();
stream.close();
return ChannelReconciliationFileContent.instance("reconciliationFile.zip", stream.toByteArray());
} catch (IOException e) {
throw new MultiFileChannelReconciliationException();
}
}
private void toZipOutputStream(ChannelBillPackage channelBillPackage ,ZipOutputStream zipOutputStream){
try (ByteArrayInputStream fis = new ByteArrayInputStream(channelBillPackage.getBillContent())) {
ZipEntry zipEntryXtv = new ZipEntry(channelBillPackage.getFilename());
zipOutputStream.putNextEntry(zipEntryXtv);
IOUtils.copy(fis, zipOutputStream);
} catch (Exception e) {
e.printStackTrace();
}
}
private Optional<Map.Entry<PayChannel, ChannelBillValidator>> findChannels(String channel) {
return validatorMap.entrySet().stream().filter(entry -> channel.equals(entry.getKey().getChannelCode())).findAny();
}
}

@ -0,0 +1,66 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile;
import org.apache.commons.io.FilenameUtils;
/**
*
* @Date 2020/11/5 17:21
* @author: zhangTao
*/
public class ChannelReconciliationFileContent {
private static String SUFFIX =".txt";
private final FileName fileName;
private final byte[] content;
private ChannelReconciliationFileContent(String fileName, byte[] content) {
this.fileName = new FileName(fileName) ;
this.content = content;
}
public String name() {
return this.fileName.getName();
}
public int length() {
return this.content.length;
}
public byte[] content() {
return this.content;
}
public static ChannelReconciliationFileContent instance(String fileName, byte[] billContent) {
if (!checkFileName(fileName)){
fileName = fileName+SUFFIX;
// throw new ChannelReconciliationFileNameSuffixException();
}
return new ChannelReconciliationFileContent(fileName, billContent);
}
private static boolean checkFileName(String fileName) {
return fileName.contains(".");
}
private class FileName {
private final String name;
private final String type;
public FileName(String name) {
this.name = name;
this.type = FilenameUtils.getExtension(name);
}
public String getName() {
return name;
}
public String getType() {
return type;
}
}
}

@ -0,0 +1,49 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile;
import lombok.Data;
/**
* @Description
* @title:
* @Date 2020/11/4 16:40
* @author: zhangTao
*/
@Data
public class ChannelReconciliationFileDTO {
private String batchId;
/**
*
*/
private String channel;
/**
*
*/
private String pid;
/**
*
*/
private String billDate;
/**
*
*/
private String billType;
/**
*
*/
private String createTime;
private String fileId;
private String filename;
private String fileType;
private String attachId;
/**
*
*/
private String attachUrl;
}

@ -0,0 +1,51 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile;
import java.util.Date;
/**
* @Description
* @title:
* @Date 2020/11/16 14:42
* @author: zhangTao
*/
public class ChannelReconciliationFileDownloadParameter {
private DownloadParameter parameter;
private boolean useCashFlag;
public ChannelReconciliationFileDownloadParameter(String pid, Date billDate, String channel, boolean isUseCash,String billType) {
this.parameter = new DownloadParameter(pid, billDate, channel,billType);
this.useCashFlag = isUseCash;
}
public String getChannel() {
return this.parameter.channel;
}
public boolean isUseCash() {
return this.useCashFlag;
}
public String pid(){
return this.parameter.pid;
}
public Date billDate(){
return this.parameter.billDate;
}
public String billType(){
return this.parameter.billType;
}
private static class DownloadParameter {
private String pid;
private String channel;
private Date billDate;
private String billType;
public DownloadParameter(String pid, Date billDate, String channel,String billType) {
this.pid = pid;
this.billDate = billDate;
this.channel = channel;
this.billType = billType;
}
}
}

@ -0,0 +1,15 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile;
/**
* @Description
* @title:
* @Date 2020/11/12 11:27
* @author: zhangTao
*/
public class ChannelReconciliationFileEmptyException extends RuntimeException {
public ChannelReconciliationFileEmptyException() {
super("渠道对账文件查询为空");
}
}

@ -0,0 +1,12 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile;
/**
* @Description
* @title:
* @Date 2020/11/19 18:35
* @author: zhangTao
*/
public class ChannelReconciliationFileNameSuffixException extends RuntimeException {
}

@ -0,0 +1,35 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.common.TimeRangeAndPageSizeQueryParameter;
/**
* @Description
* @title:
* @Date 2020/11/16 11:54
* @author: zhangTao
*/
public class ChannelReconciliationFileQueryParameter {
private TimeRangeAndPageSizeQueryParameter timeRangeAndPageSizeQueryParameter;
private String channel;
private String billType;
public ChannelReconciliationFileQueryParameter(TimeRangeAndPageSizeQueryParameter timeRangeAndPageSizeQueryParameter, String channel ,String billType) {
this.timeRangeAndPageSizeQueryParameter = timeRangeAndPageSizeQueryParameter;
this.channel = channel;
this.billType = billType;
}
public String getChannel() {
return channel;
}
public String getBillType() {
return billType;
}
public TimeRangeAndPageSizeQueryParameter getTimeRangeAndPageSizeQueryParameter() {
return timeRangeAndPageSizeQueryParameter;
}
}

@ -0,0 +1,15 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
/**
* @Description
* @title:
* @Date 2020/11/5 16:50
* @author: zhangTao
*/
public interface ChannelReconciliationFileTunnel {
PageList<ChannelReconciliationFileDTO> list(ChannelReconciliationFileQueryParameter channelReconciliationFileQueryParameter);
}

@ -0,0 +1,14 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile;
/**
* @Description
* @title:
* @Date 2020/11/6 11:24
* @author: zhangTao
*/
public class FileDownloadException extends RuntimeException {
public FileDownloadException() {
super("文件下载异常");
}
}

@ -0,0 +1,14 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile;
/**
* @Description
* @title:
* @Date 2020/11/6 11:24
* @author: zhangTao
*/
public class MultiFileChannelReconciliationException extends RuntimeException {
public MultiFileChannelReconciliationException() {
super("渠道多文件异常");
}
}

@ -0,0 +1,29 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile.common;
/**
* @Description
* @title:
* @Date 2020/11/16 13:36
* @author: zhangTao
*/
public class PageSize {
private int page;
protected int rows;
public PageSize(int page, int rows) {
this.page = page;
this.rows = rows;
}
public int getPage() {
if (page == 0) {
return 1;
}
return page;
}
public int getRows() {
return rows;
}
}

@ -0,0 +1,26 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile.common;
/**
* @Description
* @title:
* @Date 2020/11/16 11:59
* @author: zhangTao
*/
public class TimeRange {
private String startTime;
private String endTime;
public TimeRange(String startTime, String endTime) {
this.startTime = startTime;
this.endTime = endTime;
}
public String getStartTime() {
return startTime;
}
public String getEndTime() {
return endTime;
}
}

@ -0,0 +1,26 @@
package au.com.royalpay.payment.manage.management.channelreconciliationfile.common;
/**
* @Description
* @title:
* @Date 2020/11/16 13:47
* @author: zhangTao
*/
public class TimeRangeAndPageSizeQueryParameter {
private TimeRange timeRange;
private PageSize pageSize;
public TimeRangeAndPageSizeQueryParameter(TimeRange timeRange, PageSize pageSize) {
this.timeRange = timeRange;
this.pageSize = pageSize;
}
public TimeRange getTimeRange() {
return timeRange;
}
public PageSize getPageSize() {
return pageSize;
}
}

@ -0,0 +1,60 @@
package au.com.royalpay.payment.manage.management.clearing.beans;
import com.alibaba.fastjson.annotation.JSONField;
/**
* Create by Todking at 2020-12-28
*/
public class TransactionStatus {
@JSONField(name = "status")
private Integer status;
@JSONField(name = "time")
private String time;
private String statusInfo;
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getStatusInfo() {
return statusInfo;
}
public void setStatusInfo(String statusInfo) {
this.statusInfo = statusInfo;
}
public TransactionStatus toSet() {
TransactionStatus transactionStatus = new TransactionStatus();
switch (status) {
case 0:
transactionStatus.setStatusInfo("Ready To Clear");
break;
case 1:
transactionStatus.setStatusInfo("Cleared");
break;
case 2:
transactionStatus.setStatusInfo("Preauthorised");
break;
}
transactionStatus.setStatus(status);
transactionStatus.setTime(time);
return transactionStatus;
}
}

@ -1,5 +1,7 @@
package au.com.royalpay.payment.manage.management.clearing.core; package au.com.royalpay.payment.manage.management.clearing.core;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.ChannelReconciliationFileContent;
import au.com.royalpay.payment.manage.management.clearing.beans.TransactionStatus;
import au.com.royalpay.payment.manage.support.abafile.ABAFile; import au.com.royalpay.payment.manage.support.abafile.ABAFile;
import au.com.royalpay.payment.manage.tradelog.beans.ClearingLogQuery; import au.com.royalpay.payment.manage.tradelog.beans.ClearingLogQuery;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
@ -109,4 +111,8 @@ public interface CleanService {
JSONObject findSettleLog(int clearingId); JSONObject findSettleLog(int clearingId);
JSONObject findClearingDetail(int clearingId, String clientMoniker); JSONObject findClearingDetail(int clearingId, String clientMoniker);
ChannelReconciliationFileContent downloadChannelReconciliationFile(String pid, Date billDate, boolean noCache, String channel, String billType);
TransactionStatus getTransactionStatus(String transactionId);
} }

@ -3,9 +3,15 @@ package au.com.royalpay.payment.manage.management.clearing.core.impl;
import au.com.royalpay.payment.core.PaymentApi; import au.com.royalpay.payment.core.PaymentApi;
import au.com.royalpay.payment.core.beans.OrderValidationResult; import au.com.royalpay.payment.core.beans.OrderValidationResult;
import au.com.royalpay.payment.core.exceptions.InvalidShortIdException; import au.com.royalpay.payment.core.exceptions.InvalidShortIdException;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import au.com.royalpay.payment.core.impls.LogChannelValidationStorage;
import au.com.royalpay.payment.core.tasksupport.SettlementSupport; import au.com.royalpay.payment.core.tasksupport.SettlementSupport;
import au.com.royalpay.payment.core.utils.ExtParamsUtils; import au.com.royalpay.payment.core.utils.ExtParamsUtils;
import au.com.royalpay.payment.core.validation.domain.ChannelValidationTask; import au.com.royalpay.payment.core.validation.domain.ChannelValidationTask;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.ChannelReconciliationFile;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.ChannelReconciliationFileContent;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.ChannelReconciliationFileDownloadParameter;
import au.com.royalpay.payment.manage.management.clearing.beans.TransactionStatus;
import au.com.royalpay.payment.manage.management.clearing.core.CleanService; import au.com.royalpay.payment.manage.management.clearing.core.CleanService;
import au.com.royalpay.payment.manage.mappers.log.*; import au.com.royalpay.payment.manage.mappers.log.*;
import au.com.royalpay.payment.manage.mappers.payment.TaskManualSettleMapper; import au.com.royalpay.payment.manage.mappers.payment.TaskManualSettleMapper;
@ -150,8 +156,13 @@ public class CleanServiceImpl implements CleanService, ManagerTodoNoticeProvider
@Resource @Resource
private ClientIncrementalMapper clientIncrementalMapper; private ClientIncrementalMapper clientIncrementalMapper;
@Resource @Resource
private ChannelReconciliationFile channelReconciliationFile;
@Resource
private ChannelValidationTask channelValidationTask; private ChannelValidationTask channelValidationTask;
@Resource
private LogChannelValidationStorage logChannelValidationStorage;
@Resource @Resource
private ClientDeviceMapper clientDeviceMapper; private ClientDeviceMapper clientDeviceMapper;
private static final int MAX_TRACK_DAYS = 31; private static final int MAX_TRACK_DAYS = 31;
@ -163,11 +174,14 @@ public class CleanServiceImpl implements CleanService, ManagerTodoNoticeProvider
@Override @Override
public List<JSONObject> listValidatedDays(Date month) { public List<JSONObject> listValidatedDays(Date month) {
List<JSONObject> reports = validationLogMapper.listValidatedReports(month); List<JSONObject> originOriginReports = validationLogMapper.listValidatedDates(month);
List<JSONObject> topReports = new ArrayList<>(); List<OrderValidationResult> newReports = logChannelValidationStorage.listMonthReports(month);
for (JSONObject report : reports) { Map<String, JSONObject> reports = new TreeMap<>();
for (JSONObject report : originOriginReports) {
JSONObject item = new JSONObject(); JSONObject item = new JSONObject();
item.put("date", DateFormatUtils.format(report.getDate("valid_date"), "yyyy/MM/dd")); String dateStr = DateFormatUtils.format(report.getDate("valid_date"), "yyyy/MM/dd");
item.put("date", dateStr);
item.put("isOld", true);
JSONObject result = JSON.parseObject(report.getString("result")); JSONObject result = JSON.parseObject(report.getString("result"));
int warningLevel = result.getBooleanValue("valid") ? 0 : 1; int warningLevel = result.getBooleanValue("valid") ? 0 : 1;
if (!result.getJSONArray("not_exists").isEmpty()) { if (!result.getJSONArray("not_exists").isEmpty()) {
@ -175,9 +189,18 @@ public class CleanServiceImpl implements CleanService, ManagerTodoNoticeProvider
} }
item.put("warning_level", warningLevel); item.put("warning_level", warningLevel);
item.put("success", result.getBooleanValue("valid")); item.put("success", result.getBooleanValue("valid"));
topReports.add(item); reports.put(dateStr, item);
} }
return topReports; for (OrderValidationResult res : newReports) {
JSONObject item = new JSONObject();
String dateStr = DateFormatUtils.format(res.getTransDate(), "yyyy/MM/dd");
item.put("date", dateStr);
item.put("isOld", false);
item.put("warning_level", res.getWarningLevel());
item.put("success", res.getWarningLevel() == OrderValidationResult.LEVEL_SUCCESS);
reports.put(dateStr, item);
}
return new ArrayList<>(reports.values());
} }
@Override @Override
@ -1692,6 +1715,20 @@ public class CleanServiceImpl implements CleanService, ManagerTodoNoticeProvider
.orElseThrow(() -> new NotFoundException("No clearing log found for " + clientMoniker)); .orElseThrow(() -> new NotFoundException("No clearing log found for " + clientMoniker));
} }
@Override
public ChannelReconciliationFileContent downloadChannelReconciliationFile(String pid, Date billDate, boolean noCache, String channel, String billType) {
return channelReconciliationFile.download(new ChannelReconciliationFileDownloadParameter(pid, billDate, channel, noCache, billType));
}
@Override
public TransactionStatus getTransactionStatus(String transactionId) {
TransactionStatus transactionStatus = transactionMapper.getTransactionStatusById(transactionId);
if (transactionStatus == null) {
throw new ParamInvalidException("date","The transaction was not found");
}
return transactionStatus.toSet();
}
private void releaseDistributedSurcharge(JSONObject clearingDetail) { private void releaseDistributedSurcharge(JSONObject clearingDetail) {
int clientId = clearingDetail.getIntValue("client_id"); int clientId = clearingDetail.getIntValue("client_id");
BigDecimal distributedSurcharge = clearingDetail.getBigDecimal("distributed_surcharge"); BigDecimal distributedSurcharge = clearingDetail.getBigDecimal("distributed_surcharge");

@ -1,23 +1,36 @@
package au.com.royalpay.payment.manage.management.clearing.web; package au.com.royalpay.payment.manage.management.clearing.web;
import au.com.royalpay.payment.core.beans.OrderValidationChannelResult;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException; import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import au.com.royalpay.payment.core.impls.LogChannelValidationStorage;
import au.com.royalpay.payment.core.validation.domain.ChannelValidationTask;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.ChannelReconciliationFileContent;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.FileDownloadException;
import au.com.royalpay.payment.manage.management.clearing.beans.TransactionStatus;
import au.com.royalpay.payment.manage.management.clearing.core.CleanService; import au.com.royalpay.payment.manage.management.clearing.core.CleanService;
import au.com.royalpay.payment.manage.permission.manager.ManagerMapping; import au.com.royalpay.payment.manage.permission.manager.ManagerMapping;
import au.com.royalpay.payment.tools.permission.enums.ManagerRole; import au.com.royalpay.payment.tools.permission.enums.ManagerRole;
import au.com.royalpay.payment.tools.CommonConsts; import au.com.royalpay.payment.tools.CommonConsts;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import org.apache.commons.codec.Charsets;
import org.apache.commons.lang3.time.DateFormatUtils; import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils; import org.apache.commons.lang3.time.DateUtils;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.ParseException; import java.text.ParseException;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/** /**
* Created by davep on 2016-09-02. * Created by davep on 2016-09-02.
@ -28,6 +41,12 @@ public class FinancialController {
@Resource @Resource
private CleanService cleanService; private CleanService cleanService;
@Resource
private LogChannelValidationStorage logChannelValidationStorage;
@Resource
private ChannelValidationTask channelValidationTask;
@GetMapping("/validated_dates/{month}") @GetMapping("/validated_dates/{month}")
public List<JSONObject> listMonthValidatedDays(@PathVariable String month) { public List<JSONObject> listMonthValidatedDays(@PathVariable String month) {
try { try {
@ -49,6 +68,70 @@ public class FinancialController {
} }
} }
@GetMapping("/order_validation_new/{date}")
public Map<String, List<OrderValidationChannelResult>> getCheckReportNew(@PathVariable String date) {
try {
Date dt = DateUtils.parseDate(date, "yyyyMMdd");
List<OrderValidationChannelResult> orderValidationChannelResults = logChannelValidationStorage.listDailyLogs(dt);
Map<String, List<OrderValidationChannelResult>> collect = orderValidationChannelResults.stream().collect(Collectors.groupingBy(e -> e.getChannel().getChannelCode()));
return collect;
} catch (ParseException e) {
throw new ParamInvalidException("date", "error.payment.valid.invalid_date_format");
}
}
@PostMapping("/mark/resolve/message")
public void markResolveMessage(@RequestBody JSONObject jsonObject) {
logChannelValidationStorage.markResolveMessage(jsonObject.getString("log_id"), jsonObject.getString("message"));
}
@PostMapping("/redo_channel_validation/{date}")
public void redoChannelValidation(@PathVariable String date, @RequestBody JSONObject jsonObject) {
try {
Date dt = DateUtils.parseDate(date, "yyyyMMdd");
channelValidationTask.redoChannelValidation(dt, jsonObject.getString("channel"), jsonObject.getBoolean("cache"));
} catch (ParseException e) {
throw new ParamInvalidException("date", "error.payment.valid.invalid_date_format");
}
}
@GetMapping("/get/transaction/status/{transactionId}")
public TransactionStatus getTransactionStatus(@PathVariable String transactionId) {
if(transactionId.isEmpty()){
throw new ParamInvalidException("date","Transaction flow is empty");
}
return cleanService.getTransactionStatus(transactionId);
}
@GetMapping("/downloadChannelReconciliationFile")
public JSONObject downloadChannelReconciliationFile(@RequestParam(value = "pid") String pid,
@RequestParam(value = "billDate") String billDate,
@RequestParam(value = "noCache") boolean noCache,
@RequestParam(value = "billType", required = false) String billType,
@RequestParam(value = "channel") String channel,
HttpServletResponse response) {
ChannelReconciliationFileContent file = cleanService.downloadChannelReconciliationFile(pid, au.com.royalpay.payment.tools.utils.DateUtils.parseDate(billDate)
, noCache, channel, billType);
try (InputStream in = new ByteArrayInputStream(file.content())) {
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.name(), Charsets.UTF_8.name()));
response.setContentLength(file.length());
response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
OutputStream out = response.getOutputStream();
byte[] buff = new byte[1024];
int n;
while ((n = in.read(buff)) != -1) {
out.write(buff, 0, n);
}
} catch (IOException ex) {
throw new FileDownloadException();
}
return null;
}
@GetMapping("/clean_logs") @GetMapping("/clean_logs")
public JSONObject getDailyTransactions(@RequestParam String date, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) { public JSONObject getDailyTransactions(@RequestParam String date, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
try { try {

@ -0,0 +1,37 @@
package au.com.royalpay.payment.manage.mappers.log;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.ChannelReconciliationFileDTO;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.ChannelReconciliationFileQueryParameter;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.ChannelReconciliationFileTunnel;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.common.PageSize;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.common.TimeRange;
import au.com.royalpay.payment.manage.management.channelreconciliationfile.common.TimeRangeAndPageSizeQueryParameter;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import com.yixsoft.support.mybatis.autosql.annotations.AutoMapper;
/**
* @Description
* @title:
* @Date 2020/11/4 14:25
* @author: zhangTao
*/
@AutoMapper(tablename = "log_validation_attachment_batches", pkName = "batch_id")
public interface ChannelReconciliationFileTunnelMapper extends ChannelReconciliationFileTunnel {
PageList<ChannelReconciliationFileDTO> queryChannelReconciliationFile(String billType, String channel, String startTime, String endTime, PageBounds pagination);
@Override
default PageList<ChannelReconciliationFileDTO> list(ChannelReconciliationFileQueryParameter channelReconciliationFileQueryParameter){
TimeRangeAndPageSizeQueryParameter timeRangeAndPageSizeQueryParameter = channelReconciliationFileQueryParameter.getTimeRangeAndPageSizeQueryParameter();
TimeRange timeRange = timeRangeAndPageSizeQueryParameter.getTimeRange();
PageSize pageSize = timeRangeAndPageSizeQueryParameter.getPageSize();
String channel = channelReconciliationFileQueryParameter.getChannel();
String billType = channelReconciliationFileQueryParameter.getBillType();
return this.queryChannelReconciliationFile(billType,channel, timeRange.getStartTime(), timeRange.getEndTime() , new PageBounds(pageSize.getPage(), pageSize.getRows()));
}
}

@ -24,4 +24,6 @@ public interface ValidationLogMapper {
JSONObject findByDate(@Param("valid_date") Date validDate); JSONObject findByDate(@Param("valid_date") Date validDate);
List<JSONObject> listValidatedReports(@Param("month") Date month); List<JSONObject> listValidatedReports(@Param("month") Date month);
List<JSONObject> listValidatedDates(Date month);
} }

@ -1,5 +1,6 @@
package au.com.royalpay.payment.manage.mappers.payment; package au.com.royalpay.payment.manage.mappers.payment;
import au.com.royalpay.payment.manage.management.clearing.beans.TransactionStatus;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds; import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList; import com.github.miemiedev.mybatis.paginator.domain.PageList;
@ -167,4 +168,6 @@ public interface TransactionMapper {
List<JSONObject> getSettleDataDailyReport(@Param("beginTime") Date beginTime,@Param("endTime")Date endTime); List<JSONObject> getSettleDataDailyReport(@Param("beginTime") Date beginTime,@Param("endTime")Date endTime);
List<JSONObject> analysisByChannels(@Param("from") Date from, @Param("to") Date to, @Param("channels") List<String> channels); List<JSONObject> analysisByChannels(@Param("from") Date from, @Param("to") Date to, @Param("channels") List<String> channels);
TransactionStatus getTransactionStatusById(String transactionId);
} }

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="au.com.royalpay.payment.manage.mappers.log.ChannelReconciliationFileTunnelMapper">
<select id="queryChannelReconciliationFile" resultType="au.com.royalpay.payment.manage.management.channelreconciliationfile.ChannelReconciliationFileDTO">
SELECT a.batch_id ,channel, pid,bill_date,bill_type,create_time, file_id, filename, file_type,attach_id,attach_url
FROM `log_validation_attachment_batches` a
LEFT JOIN `log_validation_attachment_files` b ON a.`batch_id` = b.`batch_id`
<where>
<if test="channel != null and channel != ''">
and channel = #{channel}
</if>
<if test="startTime != null and startTime != ''">
and date_format(`bill_date`,'%Y-%m-%d') <![CDATA[>= ]]>#{startTime,jdbcType=VARCHAR}
</if>
<if test="endTime != null and endTime != ''">
and date_format(`bill_date`,'%Y-%m-%d')<![CDATA[ <= ]]> #{endTime,jdbcType=VARCHAR}
</if>
<if test="billType != null and billType != ''">
and bill_type = #{billType}
</if>
</where>
ORDER BY bill_date DESC
</select>
</mapper>

@ -10,4 +10,7 @@
<select id="listValidatedReports" resultType="com.alibaba.fastjson.JSONObject"> <select id="listValidatedReports" resultType="com.alibaba.fastjson.JSONObject">
SELECT valid_date,result FROM log_order_validation WHERE month(valid_date)=month(#{month}) and year(valid_date)=year(#{month}) SELECT valid_date,result FROM log_order_validation WHERE month(valid_date)=month(#{month}) and year(valid_date)=year(#{month})
</select> </select>
<select id="listValidatedDates" resultType="com.alibaba.fastjson.JSONObject">
SELECT valid_date,result FROM log_order_validation WHERE month(valid_date)=month(#{month}) and year(valid_date)=year(#{month})
</select>
</mapper> </mapper>

@ -1490,4 +1490,11 @@
<foreach collection="channels" open="(" close=")" separator="," item="channel">#{channel}</foreach> <foreach collection="channels" open="(" close=")" separator="," item="channel">#{channel}</foreach>
group by o.merchant_id group by o.merchant_id
</select> </select>
<select id="getTransactionStatusById" resultType="au.com.royalpay.payment.manage.management.clearing.beans.TransactionStatus">
select
t.clearing_status `status`,
t.clearing_time `time`
from pmt_transactions t
where t.transaction_id = #{transaction_id}
</select>
</mapper> </mapper>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

@ -2,83 +2,297 @@
* Created by davep on 2016-09-01. * Created by davep on 2016-09-01.
*/ */
define(['angular', 'uiRouter'], function () { define(['angular', 'uiRouter'], function () {
'use strict'; 'use strict'
var app = angular.module('orderValidApp', ['ui.router']); var app = angular.module('orderValidApp', ['ui.router'])
app.config(['$stateProvider', function ($stateProvider) { app.config([
$stateProvider.state('order_valid', { '$stateProvider',
url: '/order_validation', function ($stateProvider) {
templateUrl: '/static/payment/validation/templates/valid-calendar.html', $stateProvider
controller: 'orderValidCalendarCtrl' .state('order_valid', {
}).state('order_valid.report', { url: '/order_validation',
url: '/{date}', templateUrl: '/static/payment/validation/templates/valid-calendar.html',
templateUrl: '/static/payment/validation/templates/valid.html', controller: 'orderValidCalendarCtrl',
controller: 'orderValidationCtrl' })
}); .state('order_valid.report', {
}]); url: '/{date}',
app.controller('orderValidCalendarCtrl', ['$scope', '$http', '$filter', function ($scope, $http, $filter) { templateUrl: '/static/payment/validation/templates/valid.html',
$scope.today = new Date(); controller: 'orderValidationCtrl',
$scope.loadValidatedDates = function (month) { })
let monthStr = $filter('date')(month, 'yyyyMM'); .state('order_valid.report_new', {
$http.get('/sys/financial/validated_dates/' + monthStr).then(function (resp) { url: '/new/{date}',
$scope.validatedDates = resp.data; 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; // old
$scope.startValid = function (forceRebuild) { app.controller('orderValidationCtrl', [
$scope.report = {loading: true}; '$scope',
$http.get('/sys/financial/order_validations/' + $scope.date, { '$http',
params: { '$filter',
use_cache: !forceRebuild '$stateParams',
}, 'commonDialog',
timeout: 300000 function ($scope, $http, $filter, $stateParams, commonDialog) {
}).then(function (resp) { $scope.date = $stateParams.date
$scope.report = resp.data; $scope.startValid = function (forceRebuild) {
$scope.notExistsKeys = []; $scope.report = { loading: true }
$scope.notEqualsKeys = []; $http
angular.forEach($scope.report.not_exists, function (item) { .get('/sys/financial/order_validations/' + $scope.date, {
angular.forEach(item, function (val, key) { params: {
if ($scope.notExistsKeys.indexOf(key) < 0) { use_cache: !forceRebuild,
$scope.notExistsKeys.push(key); },
} timeout: 300000,
}) })
}); .then(
angular.forEach($scope.report.not_equals, function (item) { function (resp) {
angular.forEach(item, function (val, key) { $scope.report = resp.data
if ($scope.notExistsKeys.indexOf(key) < 0) { $scope.notExistsKeys = []
$scope.notExistsKeys.push(key); $scope.notEqualsKeys = []
} angular.forEach($scope.report.not_exists, function (item) {
}) angular.forEach(item, function (val, key) {
}); if ($scope.notExistsKeys.indexOf(key) < 0) {
}, function (resp) { $scope.notExistsKeys.push(key)
commonDialog.alert({title: 'Error', content: resp.data.message, type: 'error'}); }
$scope.report = null; })
})
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 () { $scope.fixReport = function () {
var datePattern = $filter('date')($scope.valid.date, 'yyyyMMdd'); var datePattern = $filter('date')($scope.valid.date, 'yyyyMMdd')
$http.get('/sys/financial/order_validations', { $http
params: { .get('/sys/financial/order_validations', {
date: datePattern, params: {
fix: true date: datePattern,
} fix: true,
}).then(function (resp) { },
commonDialog.alert({title: 'Success', content: '修复完毕', type: 'success'}) })
}, function (resp) { .then(
commonDialog.alert({title: 'Error', content: resp.data.message, type: 'error'}) 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 (merchant) {
sessionStorage.setItem('channel', JSON.stringify($scope.channelList))
$uibModal
.open({
templateUrl: '/static/payment/validation/templates/handle_desc.html',
controller: [
'$scope',
'$http',
'commonDialog',
'merchantInfo',
function ($scope, $http, commonDialog, merchantInfo) {
if (merchantInfo.resolve_msg) {
$scope.message = merchantInfo.resolve_msg
}
$scope.confirm = function () {
$http.post('/sys/financial/mark/resolve/message', { log_id: merchantInfo.log_id, message: $scope.message }).then(
function () {
$scope.$close()
},
function (resp) {
commonDialog.alert({ title: 'failed', content: resp.data.message, type: 'error' })
}
)
}
},
],
resolve: {
merchantInfo: [
'$stateParams',
function () {
return merchant
},
],
},
})
.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' })
}
)
}
},
])
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()">OK</button>
</div>
<div class="btn-group">
<button class="btn btn-danger" type="button" ng-click="$dismiss()">Cancel</button>
</div>
</div>

@ -7,19 +7,35 @@
</ol> </ol>
</section> </section>
<section class="content"> <section class="content">
<div class="box"> <div class="box">
<div class="box-body"> <div class="box-body">
<div royal-calendar month-change="loadValidatedDates($month)"> <div royal-calendar month-change="loadValidatedDates($month)">
<a class="rc-full" role="button" ui-sref=".report({date:(day|date:'yyyyMMdd')})" <a class="rc-full" role="button" ng-click="checkDetail((day|date:'yyyy/MM/dd'))"
style="font-size: 40px" ng-if="day<=today"> style="font-size: 40px" ng-if="day<=today">
<i class="fa" <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-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-if="findReport((day|date:'yyyy/MM/dd'))!=null"></i>
</a> </a>
</div> </div>
</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> </div>
</section> </section>
</div> </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)">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