parent
3ac82ce0e3
commit
e43b4b0f42
@ -0,0 +1,17 @@
|
||||
package au.com.royalpay.payment.manage.system.core;
|
||||
|
||||
import au.com.royalpay.payment.manage.system.core.beans.TradeSecureFile;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Create by yixian at 2019-01-08 3:17
|
||||
*/
|
||||
public interface TradeSecureService {
|
||||
void uploadSecureReportYesterday();
|
||||
|
||||
void uploadSecureReport(Date date);
|
||||
|
||||
TradeSecureFile getSecureReportFile(Date date);
|
||||
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
package au.com.royalpay.payment.manage.system.core.beans;
|
||||
|
||||
import au.com.royalpay.payment.tools.defines.TradeType;
|
||||
import au.com.royalpay.payment.tools.env.PlatformEnvironment;
|
||||
import au.com.royalpay.payment.tools.exceptions.ServerErrorException;
|
||||
import au.com.royalpay.payment.tools.utils.CurrencyAmountUtils;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Create by yixian at 2019-01-08 3:27
|
||||
*/
|
||||
public class TradeSecureFile {
|
||||
private static final DateTimeZone zone = DateTimeZone.forTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
|
||||
private final String pid;
|
||||
private final DateTime transDate;
|
||||
private final DateTime createTime;
|
||||
private List<TradeItem> tradeItems;
|
||||
private byte[] content;
|
||||
|
||||
public TradeSecureFile(String pid, Date transDate) {
|
||||
this.pid = pid;
|
||||
this.transDate = new DateTime(transDate).withZoneRetainFields(zone).withMillisOfDay(0);
|
||||
this.tradeItems = new ArrayList<>();
|
||||
this.createTime = DateTime.now(zone);
|
||||
}
|
||||
|
||||
public DateTime getTransDate() {
|
||||
return transDate;
|
||||
}
|
||||
|
||||
public Date getFromTime() {
|
||||
return transDate.withZone(DateTimeZone.forTimeZone(TimeZone.getDefault())).toDate();
|
||||
}
|
||||
|
||||
public Date getToTime() {
|
||||
return transDate.plusDays(1).withZone(DateTimeZone.forTimeZone(TimeZone.getDefault())).toDate();
|
||||
}
|
||||
|
||||
public TradeSecureFile addTransactions(List<JSONObject> transactions) {
|
||||
tradeItems.addAll(transactions.stream().map(TradeItem::new).collect(Collectors.toList()));
|
||||
return this;
|
||||
}
|
||||
|
||||
public void writeToHttp(HttpServletResponse response) {
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setHeader("Content-Disposition", "attachment; filename=" + filename());
|
||||
try (OutputStream ous = response.getOutputStream()) {
|
||||
ous.write(content());
|
||||
ous.flush();
|
||||
} catch (IOException e) {
|
||||
throw new ServerErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String filename() {
|
||||
return String.join("_", transDate.toString("yyMMdd"), pid, createTime.toString("yyMMddHHmmss"));
|
||||
}
|
||||
|
||||
public byte[] content() {
|
||||
return content == null ? build() : content;
|
||||
}
|
||||
|
||||
private byte[] build() {
|
||||
|
||||
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
PrintWriter writer = new PrintWriter(new OutputStreamWriter(bos, StandardCharsets.UTF_8))) {
|
||||
writer.println(headerLine());
|
||||
for (TradeItem item : tradeItems) {
|
||||
writer.println(item.line());
|
||||
}
|
||||
content = bos.toByteArray();
|
||||
return content;
|
||||
} catch (IOException e) {
|
||||
throw new ServerErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String headerLine() {
|
||||
int totalCount = tradeItems.size();
|
||||
BigDecimal totalCredit = tradeItems.stream().filter(TradeItem::isCredit).map(TradeItem::getClearingAmount)
|
||||
.reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
|
||||
BigDecimal totalDebit = tradeItems.stream().filter(TradeItem::isDebit).map(TradeItem::getClearingAmount)
|
||||
.reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
|
||||
String date = transDate.toString("yyyy-MM-dd");
|
||||
String[] columns = {String.valueOf(totalCount), totalCredit.toPlainString(), totalDebit.toPlainString(), date, pid};
|
||||
return String.join("|", columns);
|
||||
}
|
||||
|
||||
class TradeItem {
|
||||
|
||||
private String clientMoniker;
|
||||
private String orderId;
|
||||
private String channel;
|
||||
private TradeType gateway;
|
||||
private BigDecimal price;
|
||||
private BigDecimal clearingAmount;
|
||||
private String currency;
|
||||
private BigDecimal exchangeRate;
|
||||
private String transactionType;
|
||||
private Date transactionTime;
|
||||
|
||||
public TradeItem(JSONObject item) {
|
||||
clientMoniker = item.getString("client_moniker");
|
||||
transactionType = item.getString("transaction_type");
|
||||
orderId = isCredit() ? item.getString("order_id") : item.getString("out_refund_id");
|
||||
channel = item.getString("order_channel");
|
||||
gateway = TradeType.fromGatewayNumber(item.getIntValue("gateway"));
|
||||
currency = item.getString("transaction_currency");
|
||||
price = CurrencyAmountUtils.scale(item.getBigDecimal("transaction_amount"), currency);
|
||||
clearingAmount = CurrencyAmountUtils.scale(item.getBigDecimal("clearing_amount"), PlatformEnvironment.getEnv().getForeignCurrency());
|
||||
exchangeRate = item.getBigDecimal("exchange_rate");
|
||||
transactionTime = item.getDate("transaction_time");
|
||||
}
|
||||
|
||||
public String line() {
|
||||
String[] columns = {clientMoniker, orderId, channel, gateway.toString(), price.toPlainString(), clearingAmount.toPlainString(), currency,
|
||||
exchangeRate.toPlainString(), filterStatus(), new DateTime(transactionTime).withZone(zone).toString()};
|
||||
return String.join("|", columns);
|
||||
}
|
||||
|
||||
private String filterStatus() {
|
||||
return isCredit() ? "SUCCESS" : "REFUND";
|
||||
}
|
||||
|
||||
public boolean isCredit() {
|
||||
return "Credit".equals(transactionType);
|
||||
}
|
||||
|
||||
public boolean isDebit() {
|
||||
return "Debit".equals(transactionType);
|
||||
}
|
||||
|
||||
public BigDecimal getClearingAmount() {
|
||||
return clearingAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
package au.com.royalpay.payment.manage.system.core.impl;
|
||||
|
||||
import au.com.royalpay.payment.core.exceptions.ChannelNetworkException;
|
||||
import au.com.royalpay.payment.manage.mappers.payment.TransactionMapper;
|
||||
import au.com.royalpay.payment.manage.system.core.TradeSecureService;
|
||||
import au.com.royalpay.payment.manage.system.core.beans.TradeSecureFile;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.jcraft.jsch.*;
|
||||
import org.apache.commons.vfs2.FileSystemOptions;
|
||||
import org.apache.commons.vfs2.provider.sftp.SftpClientFactory;
|
||||
import org.apache.commons.vfs2.provider.sftp.SftpFileSystemConfigBuilder;
|
||||
import org.joda.time.DateTime;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Create by yixian at 2019-01-08 3:26
|
||||
*/
|
||||
@Service
|
||||
public class TradeSecureServiceHanyinImpl implements TradeSecureService {
|
||||
@Value("${app.hanyin-secure.pid:ROYALPAY}")
|
||||
private String pid;
|
||||
@Value("${app.hanyin-secure.sftp-host}")
|
||||
private String sftpHost;
|
||||
@Value("${app.hanyin-secure.sftp-port}")
|
||||
private int sftpPort;
|
||||
@Value("${app.hanyin-secure.sftp-username}")
|
||||
private String sftpUsername;
|
||||
@Value("${app.hanyin-secure.sftp-pwd}")
|
||||
private String sftpPwd;
|
||||
@Resource
|
||||
private TransactionMapper transactionMapper;
|
||||
|
||||
@Override
|
||||
public void uploadSecureReportYesterday() {
|
||||
uploadSecureReport(DateTime.now().plusDays(-1).withMillisOfDay(0).toDate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uploadSecureReport(Date date) {
|
||||
TradeSecureFile file = getSecureReportFile(date);
|
||||
sftpUpload(file);
|
||||
}
|
||||
|
||||
private void sftpUpload(TradeSecureFile file) {
|
||||
Session session = null;
|
||||
ChannelSftp command = null;
|
||||
try {
|
||||
session = initSFTPConnection();
|
||||
Channel channel = session.openChannel("sftp");
|
||||
channel.connect();
|
||||
command = (ChannelSftp) channel;
|
||||
command.ls("/royalpay");
|
||||
String dir = "/royalpay/" + file.getTransDate().toString("yyyyMMdd");
|
||||
command.rmdir(dir);
|
||||
command.mkdir(dir);
|
||||
String dest = dir + file.filename();
|
||||
command.put(new ByteArrayInputStream(file.content()), dest);
|
||||
} catch (IOException | JSchException | SftpException e) {
|
||||
throw new ChannelNetworkException("Upload Secure file failed", e);
|
||||
} finally {
|
||||
if (command != null && command.isConnected()) {
|
||||
command.exit();
|
||||
session.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Session initSFTPConnection() throws IOException {
|
||||
FileSystemOptions fso = new FileSystemOptions();
|
||||
SftpFileSystemConfigBuilder.getInstance().setStrictHostKeyChecking(fso, "no");
|
||||
return SftpClientFactory.createConnection(sftpHost, sftpPort,
|
||||
sftpUsername.toCharArray(), sftpPwd.toCharArray(), fso);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TradeSecureFile getSecureReportFile(Date date) {
|
||||
TradeSecureFile file = new TradeSecureFile(pid, date);
|
||||
Date from = file.getFromTime();
|
||||
Date to = file.getToTime();
|
||||
List<JSONObject> credits = transactionMapper.listCreditTransactionsForSecure(from, to);
|
||||
file.addTransactions(credits);
|
||||
List<JSONObject> debits = transactionMapper.listDebitTransactionsForSecure(from, to);
|
||||
file.addTransactions(debits);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
package au.com.royalpay.payment.manage.task;
|
||||
|
||||
import au.com.royalpay.payment.manage.system.core.TradeSecureService;
|
||||
import au.com.royalpay.payment.tools.scheduler.SynchronizedScheduler;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* Create by yixian at 2019-01-08 3:13
|
||||
*/
|
||||
@Component
|
||||
@ConditionalOnProperty(value = "app.run-tasks", havingValue = "true")
|
||||
public class SecureTask {
|
||||
@Resource
|
||||
private SynchronizedScheduler synchronizedScheduler;
|
||||
@Resource
|
||||
private TradeSecureService tradeSecureService;
|
||||
|
||||
@Scheduled(cron = "0 0 3 * * *")
|
||||
public void pushSecureFile(){
|
||||
synchronizedScheduler.executeProcess("task:secure_file_uploading",600_000,()->tradeSecureService.uploadSecureReportYesterday());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue