diff --git a/pom.xml b/pom.xml index fcc8224a2..1e0300dc8 100644 --- a/pom.xml +++ b/pom.xml @@ -36,6 +36,12 @@ au.com.royalpay.payment jd-core + + com.github.stuxuhai + jpinyin + 1.1.7 + + au.com.royalpay.payment bestpay-core diff --git a/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ATOBulkData.java b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ATOBulkData.java new file mode 100644 index 000000000..c36d06253 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ATOBulkData.java @@ -0,0 +1,93 @@ +package au.com.royalpay.payment.manage.analysis.beans.ato; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Create by yixian at 2018-08-30 18:38 + */ +public class ATOBulkData { + + private IntermediaryData intermediary; + + public ATOBulkData(IntermediaryData intermediary) { + this.intermediary = intermediary; + } + + public String outputBTTPS() { + StringBuilder builder = new StringBuilder(); + intermediary.buildLine(builder); + return builder.toString(); + } + + public static class IntermediaryData implements ATOBulkLine { + private final String identifier = "IDENTREGISTER"; + private final String version = "BTPSV001.0"; + private String abn; + private Date createTime; + private String fileReference; + private String name; + private ContactInfo contactInfo; + private AddressInfo address; + private List reportingParties = new ArrayList<>(); + + public IntermediaryData(String abn, String name, String fileReference) { + this.abn = abn; + this.fileReference = fileReference; + this.name = name; + this.createTime = new Date(); + } + + public IntermediaryData setContactInfo(ContactInfo contactInfo) { + this.contactInfo = contactInfo; + return this; + } + + public IntermediaryData setAddress(AddressInfo address) { + this.address = address; + return this; + } + + @Override + public StringBuilder buildLine(StringBuilder builder) { + StringBuilder line = new StringBuilder(); + appendNParam(line, 1400, 4); + appendAParam(line, identifier, 13); + appendAParam(line, version, 10); + appendAParam(line, abn, 11); + appendDTParam(line, createTime, 28); + appendAParam(line, fileReference, 16); + appendAParam(line, name, 200); + appendAParam(line, contactInfo.getContactName(), 40); + appendNParam(line, contactInfo.getPhoneAreaCode(), 2); + appendAParam(line, contactInfo.getPhoneNumber(), 15); + appendAParam(line, address.getAddress(), 38 * 2); + appendAParam(line, address.getSuburb(), 27); + appendAParam(line, address.getState(), 3); + appendNParam(line, address.getPostCode(), 4); + appendAParam(line, address.getCountry(), 50); + appendAParam(line, contactInfo.getEmail(), 76); + appendFiller(line, 825); + + builder.append(line); + + for (ReportingPartyData partyData : reportingParties) { + partyData.buildLine(builder); + } + + TotalDataRecord total = new TotalDataRecord() + .setReportPartyCount(reportingParties.size()) + .setBusinessCount(reportingParties.stream().mapToInt(ReportingPartyData::businessCount).sum()) + .setTransactionsCount(reportingParties.stream().mapToInt(ReportingPartyData::transactionCount).sum()); + total.buildLine(builder); + return builder; + } + + public void addReportingParty(ReportingPartyData reportingParty) { + reportingParties.add(reportingParty); + } + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ATOBulkLine.java b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ATOBulkLine.java new file mode 100644 index 000000000..4b11067e8 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ATOBulkLine.java @@ -0,0 +1,70 @@ +package au.com.royalpay.payment.manage.analysis.beans.ato; + +import com.github.stuxuhai.jpinyin.PinyinException; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.joda.time.DateTime; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; + +import java.util.Date; + +/** + * Create by yixian at 2018-08-30 21:11 + */ +public interface ATOBulkLine { + StringBuilder buildLine(StringBuilder builder); + + default StringBuilder appendAParam(StringBuilder line, String content, int length) { + content = content == null ? "" : StringUtils.trim(content); + content = StringUtils.remove(StringUtils.remove(content, '\r'), '\n'); + int contentCharacterLength = content.getBytes().length; + int contentLength = content.length(); + if (contentCharacterLength != contentLength) { + try { + content = CharacterUtils.convertToAlphaBet(content); + } catch (PinyinException e) { + e.printStackTrace(); + content = ""; + } + } + content = content.replace("?", " "); + if (content.getBytes().length != content.length()) { + content = ""; + } + line.append(StringUtils.left(StringUtils.rightPad(content, length, " "), length)); + return line; + } + + default StringBuilder appendDParam(StringBuilder line, Date date, int len) { + String dateStr = DateFormatUtils.format(date, "yyyyMMdd"); + return appendAParam(line, dateStr, len); + } + + default StringBuilder appendDTParam(StringBuilder line, Date date, int len) { + DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSZZ"); + String dateStr = formatter.print(new DateTime(date)); + return appendAParam(line, dateStr, len); + } + + default StringBuilder appendNParam(StringBuilder line, int num, int len) { + line.append(StringUtils.right(StringUtils.leftPad(num + "", len, "0"), len)); + return line; + } + + default StringBuilder appendNParam(StringBuilder line, String num, int len) { + num = num == null ? "" : StringUtils.trim(num); + line.append(StringUtils.right(StringUtils.leftPad(num, len, "0"), len)); + return line; + } + + default StringBuilder appendNSParam(StringBuilder line, int num, int len) { + line.append(StringUtils.right(StringUtils.leftPad(num + "", len, " "), len)); + return line; + } + + default StringBuilder appendFiller(StringBuilder line, int len) { + line.append(StringUtils.repeat(" ", len)).append("\r\n"); + return line; + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/AddressInfo.java b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/AddressInfo.java new file mode 100644 index 000000000..a59de68b0 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/AddressInfo.java @@ -0,0 +1,47 @@ +package au.com.royalpay.payment.manage.analysis.beans.ato; + +/** + * Create by yixian at 2018-08-30 21:17 + */ +public class AddressInfo { + private String address; + private String suburb; + private String state; + private String postCode; + private String country; + + public AddressInfo(String address, String suburb, String state, String postCode, String country) { + this.address = address; + this.suburb = suburb; + this.state = state; + if (!postCode.matches("^\\d{4}$")) { + postCode = "9999"; + country = "OTH"; + } + this.postCode = postCode; + if (country != null && country.length() != 3) { + country = "OTH"; + } + this.country = country; + } + + public String getAddress() { + return address; + } + + public String getSuburb() { + return suburb; + } + + public String getState() { + return state; + } + + public String getPostCode() { + return postCode; + } + + public String getCountry() { + return "AUS".equals(country) ? "" : country; + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/BusinessData.java b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/BusinessData.java new file mode 100644 index 000000000..3d0498c01 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/BusinessData.java @@ -0,0 +1,121 @@ +package au.com.royalpay.payment.manage.analysis.beans.ato; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Create by yixian at 2018-08-30 21:21 + */ +public class BusinessData implements ATOBulkLine { + private final String identifier = "BIDR"; + private String customer; + private Date paymentFacility; + private String surName; + private String firstName; + private String secondName; + private Date birth; + private String abn; + private String acn; + private String registeredName; + private String tradingName; + private AddressInfo address; + private AddressInfo postalAddress; + private ContactInfo contactInfo; + private String mchId; + private String category; + private String lodgment; + + public BusinessData(Date paymentFacility, String abn, String acn, String registeredName, String tradingName, String mchId, String category, String lodgment) { + this.paymentFacility = paymentFacility; + if (abn != null) { + abn = abn.replaceAll("\\D", ""); + if (abn.length() != 11) { + abn = ""; + } + } + this.abn = abn; + if (acn != null) { + acn = acn.replaceAll("\\D", ""); + if (acn.length() != 9) { + acn = ""; + } + } + this.acn = acn; + this.registeredName = registeredName; + this.tradingName = tradingName; + this.mchId = mchId; + this.customer = mchId; + this.category = category; + this.lodgment = lodgment; + } + + public BusinessData setAddress(AddressInfo address) { + this.address = address; + return this; + } + + public BusinessData setPostalAddress(AddressInfo postalAddress) { + this.postalAddress = postalAddress; + return this; + } + + public BusinessData setContactInfo(ContactInfo contactInfo) { + this.contactInfo = contactInfo; + return this; + } + + private List transactions = new ArrayList<>(); + + @Override + public StringBuilder buildLine(StringBuilder builder) { + StringBuilder line = new StringBuilder(); + appendNParam(line, 1400, 4); + appendAParam(line, identifier, 4); + appendAParam(line, customer, 25); + appendDParam(line, paymentFacility, 8); + appendAParam(line, surName, 40); + appendAParam(line, firstName, 40); + appendAParam(line, secondName, 40); + appendAParam(line, null, 8); + appendNParam(line, abn, 11); + appendNParam(line, acn, 9); + appendAParam(line, registeredName, 200); + appendAParam(line, tradingName, 200); + appendAParam(line, address.getAddress(), 38 * 2); + appendAParam(line, address.getSuburb(), 27); + appendAParam(line, address.getState(), 3); + appendNParam(line, address.getPostCode(), 4); + appendAParam(line, address.getCountry(), 50); + appendAParam(line, postalAddress.getAddress(), 38 * 2); + appendAParam(line, postalAddress.getSuburb(), 27); + appendAParam(line, postalAddress.getState(), 3); + appendNParam(line, postalAddress.getPostCode(), 4); + appendAParam(line, postalAddress.getCountry(), 50); + appendAParam(line, contactInfo.getContactName(), 40); + appendNParam(line, contactInfo.getPhoneAreaCode(), 2); + appendAParam(line, contactInfo.getPhoneNumber(), 15); + appendAParam(line, contactInfo.getEmail(), 76); + appendAParam(line, mchId, 20); + appendAParam(line, category, 100); + appendAParam(line, lodgment, 1); + appendFiller(line, 237); + + builder.append(line); + + for (TransactionSummaryData trans : transactions) { + trans.buildLine(builder); + } + return builder; + } + + public int transactionCount() { + return transactions.size(); + } + + public void addTransaction(TransactionSummaryData transactionSummaryData) { + //todo system account number + transactionSummaryData.fillSystemInfo(mchId, "Merchant Acquiring System", mchId); + transactions.add(transactionSummaryData); + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/CharacterUtils.java b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/CharacterUtils.java new file mode 100644 index 000000000..5ea6b75ad --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/CharacterUtils.java @@ -0,0 +1,53 @@ +package au.com.royalpay.payment.manage.analysis.beans.ato; + +import com.github.stuxuhai.jpinyin.PinyinException; +import com.github.stuxuhai.jpinyin.PinyinFormat; +import com.github.stuxuhai.jpinyin.PinyinHelper; +import org.apache.commons.lang3.StringUtils; + +import java.util.stream.Collectors; + +/** + * Create by yixian at 2018-09-06 9:03 + */ +public class CharacterUtils { + + public static String convertToAlphaBet(String source) throws PinyinException { + return convertFullWidthToHalfWidth(convertToPinYin(source)); + } + + public static String convertToPinYin(String source) throws PinyinException { + return PinyinHelper.convertToPinyinString(source, "", PinyinFormat.WITHOUT_TONE).toUpperCase(); + } + + public static String convertFullWidthToHalfWidth(String source) { + if (StringUtils.isEmpty(source)) { + return source; + } + + return source.chars().map(ch -> { + if (ch == '\u3000') { + return '\u0020'; + } + if (isFullWidth((char) ch)) { + return (char) (ch - 65248); + } + return (char) ch; + }).filter(CharacterUtils::isHalfWidth) + .mapToObj(chInt -> "" + (char) chInt).collect(Collectors.joining()); + } + + private static boolean isHalfWidth(int ch) { + return ch >= 32 && ch <= 126; + } + + private static boolean isFullWidth(int ch) { + if (ch == '\u3000') return true; + + int i = ch - 65248; + if (i < 32) return false; + return isHalfWidth((char) i); + } + + +} diff --git a/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ContactInfo.java b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ContactInfo.java new file mode 100644 index 000000000..bf2cbadf1 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ContactInfo.java @@ -0,0 +1,88 @@ +package au.com.royalpay.payment.manage.analysis.beans.ato; + +import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator; + +/** + * Create by yixian at 2018-08-30 21:19 + */ +public class ContactInfo { + private String contactName; + private int phoneAreaCode; + private String phoneNumber; + private String email; + + public ContactInfo(String contactName, String phoneNumber, String email) { + this.contactName = contactName; + if (isPhoneNumber(phoneNumber)) { + phoneNumber = phoneNumber.replace(" ", ""); + String auPhoneNumber = formatAustralianPhoneNumber(phoneNumber); + if (auPhoneNumber != null) { + String subPhone = auPhoneNumber.substring(3); + if (!subPhone.startsWith("1300") && !subPhone.startsWith("1800")) { + this.phoneAreaCode = Integer.parseInt(subPhone.substring(0, 1)); + if (4 == phoneAreaCode) { + this.phoneNumber = subPhone.substring(1, 3) + " " + subPhone.substring(3, 6) + " " + subPhone.substring(6); + } else { + this.phoneNumber = subPhone.substring(1, 5) + " " + subPhone.substring(5); + } + } + + } else { + this.phoneNumber = formatOtherPhoneNumber(phoneNumber); + } + } + EmailValidator validator = new EmailValidator(); + this.email = validator.isValid(email, null) ? email : ""; + } + + private boolean isPhoneNumber(String phoneNumber) { + return phoneNumber.matches("^\\+?\\d+$"); + } + + private String formatAustralianPhoneNumber(String phoneNumber) { + if (phoneNumber.startsWith("+61") && phoneNumber.length() == 12) { + return phoneNumber; + } + if (phoneNumber.startsWith("61") && phoneNumber.length() == 11) { + return "+" + phoneNumber; + } + if (phoneNumber.startsWith("0") && phoneNumber.length() == 10) { + return "+61" + phoneNumber.substring(1); + } + if (phoneNumber.length() == 9) { + return "+61" + phoneNumber; + } + return null; + } + + private String formatOtherPhoneNumber(String phoneNumber) { + String num = phoneNumber.replace(" ", ""); + if (num.startsWith("+")) { + return num.replace("+", ""); + } + if (num.startsWith("00")) { + return num.substring(2); + } + if (num.startsWith("1") && num.length() == 11) { + //中国手机号 + return "86" + num; + } + return null; + } + + public String getContactName() { + return contactName; + } + + public int getPhoneAreaCode() { + return phoneAreaCode; + } + + public String getPhoneNumber() { + return phoneNumber; + } + + public String getEmail() { + return email; + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ReportingPartyData.java b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ReportingPartyData.java new file mode 100644 index 000000000..e3644757e --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/ReportingPartyData.java @@ -0,0 +1,107 @@ +package au.com.royalpay.payment.manage.analysis.beans.ato; + +import org.apache.commons.lang3.time.DateUtils; + +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * Create by yixian at 2018-08-30 21:13 + */ +public class ReportingPartyData implements ATOBulkLine { + private final String identifier = "RPDR"; + private Date periodStart; + private Date periodEnd; + private String abn; + private String branchNumber; + private String registerName; + private String tradingName; + private AddressInfo address; + private AddressInfo postalAddress; + private ContactInfo contactInfo; + private String softwareProductType; + + private Map businesses = new HashMap<>(); + + public ReportingPartyData(Date periodStart, Date periodEnd, String abn, String branchNumber, String registerName, String softwareProductType) { + this.periodStart = DateUtils.truncate(periodStart, Calendar.DATE); + this.periodEnd = DateUtils.truncate(periodEnd, Calendar.DATE); + this.abn = abn; + this.branchNumber = branchNumber; + this.registerName = registerName; + this.softwareProductType = softwareProductType; + } + + public ReportingPartyData setTradingName(String tradingName) { + this.tradingName = tradingName; + return this; + } + + public ReportingPartyData setAddress(AddressInfo address) { + this.address = address; + return this; + } + + public ReportingPartyData setPostalAddress(AddressInfo postalAddress) { + this.postalAddress = postalAddress; + return this; + } + + public ReportingPartyData setContactInfo(ContactInfo contactInfo) { + this.contactInfo = contactInfo; + return this; + } + + @Override + public StringBuilder buildLine(StringBuilder builder) { + StringBuilder line = new StringBuilder(); + appendNParam(line, 1400, 4); + appendAParam(line, identifier, 4); + appendDParam(line, periodStart, 8); + appendDParam(line, periodEnd, 8); + appendNParam(line, abn, 11); + appendNParam(line, branchNumber, 3); + appendAParam(line, registerName, 200); + appendAParam(line, tradingName, 200); + appendAParam(line, address.getAddress(), 38 * 2); + appendAParam(line, address.getSuburb(), 27); + appendAParam(line, address.getState(), 3); + appendNParam(line, address.getPostCode(), 4); + appendAParam(line, address.getCountry(), 50); + appendAParam(line, postalAddress.getAddress(), 38 * 2); + appendAParam(line, postalAddress.getSuburb(), 27); + appendAParam(line, postalAddress.getState(), 3); + appendNParam(line, postalAddress.getPostCode(), 4); + appendAParam(line, postalAddress.getCountry(), 50); + appendAParam(line, contactInfo.getContactName(), 40); + appendNParam(line, contactInfo.getPhoneAreaCode(), 2); + appendAParam(line, contactInfo.getPhoneNumber(), 15); + appendAParam(line, contactInfo.getEmail(), 76); + appendAParam(line, softwareProductType, 80); + appendFiller(line, 429); + + builder.append(line); + businesses.values().stream() + .filter(biz -> biz.transactionCount() > 0) + .forEach(biz -> biz.buildLine(builder)); + return builder; + } + + public int businessCount() { + return (int) businesses.values().stream().filter(biz -> biz.transactionCount() > 0).count(); + } + + public int transactionCount() { + return businesses.values().stream().mapToInt(BusinessData::transactionCount).sum(); + } + + public BusinessData findBusiness(Integer clientId) { + return businesses.get(clientId); + } + + public void addBusiness(Integer clientId, BusinessData biz) { + businesses.put(clientId, biz); + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/TotalDataRecord.java b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/TotalDataRecord.java new file mode 100644 index 000000000..4231dd587 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/TotalDataRecord.java @@ -0,0 +1,46 @@ +package au.com.royalpay.payment.manage.analysis.beans.ato; + +/** + * Create by yixian at 2018-08-30 21:35 + */ +public class TotalDataRecord implements ATOBulkLine { + private final String identifier = "FILE-TOTAL"; + private int reportPartyCount; + private int businessCount; + private int transactionsCount; + + + public TotalDataRecord setReportPartyCount(int reportPartyCount) { + this.reportPartyCount = reportPartyCount; + return this; + } + + public TotalDataRecord setBusinessCount(int businessCount) { + this.businessCount = businessCount; + return this; + } + + public TotalDataRecord setTransactionsCount(int transactionsCount) { + this.transactionsCount = transactionsCount; + return this; + } + + @Override + public StringBuilder buildLine(StringBuilder builder) { + StringBuilder line = new StringBuilder(); + appendNParam(line, 1400, 4); + appendAParam(line, identifier, 10); + appendNParam(line, getRecords(), 10); + appendNParam(line, reportPartyCount, 10); + appendNParam(line, businessCount, 10); + appendNParam(line, transactionsCount, 10); + appendFiller(line, 1346); + + builder.append(line); + return builder; + } + + private int getRecords() { + return reportPartyCount + businessCount + transactionsCount + 2; + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/TransactionSummaryData.java b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/TransactionSummaryData.java new file mode 100644 index 000000000..b72202d0a --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/analysis/beans/ato/TransactionSummaryData.java @@ -0,0 +1,82 @@ +package au.com.royalpay.payment.manage.analysis.beans.ato; + +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.lang3.time.DateUtils; +import org.joda.time.DateTime; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * Create by yixian at 2018-08-30 21:30 + */ +public class TransactionSummaryData implements ATOBulkLine { + private final String identifier = "TSDR"; + private String customer; + private String description; + private String accountNumber; + private String settleAccountName; + private String settleBSB; + private String settleAccountNo; + private Date periodStart; + private Date periodEnd; + private String currency = "AUD"; + private BigDecimal grossPayment; + private int transactionCount; + private BigDecimal totalRefund; + private int refundCount; + private BigDecimal cashoutAmount = BigDecimal.ZERO; + private int cashoutCount = 0; + private BigDecimal cashoutComponentAmount = BigDecimal.ZERO; + + public TransactionSummaryData(JSONObject analysis, DateTime startOfMon, DateTime endOfMon) { + settleAccountName = analysis.getString("account_name"); + settleBSB = analysis.getString("bsb_no"); + settleAccountNo = analysis.getString("account_no").replaceAll("\\D", ""); + periodStart = analysis.getDate("period_start"); + periodEnd = analysis.getDate("period_end"); + if (DateUtils.isSameDay(periodStart, periodEnd)) { + if (DateUtils.isSameDay(periodStart, startOfMon.toDate())) { + periodEnd = DateUtils.addDays(periodEnd, 1); + } else { + periodStart = DateUtils.addDays(periodStart, -1); + } + } + grossPayment = analysis.getBigDecimal("gross_payment"); + transactionCount = analysis.getIntValue("pay_count"); + totalRefund = analysis.getBigDecimal("total_refund"); + refundCount = analysis.getIntValue("refund_count"); + } + + public void fillSystemInfo(String customer, String systemDesc, String systemAccount) { + this.customer = customer; + this.description = systemDesc; + this.accountNumber = systemAccount; + } + + @Override + public StringBuilder buildLine(StringBuilder builder) { + StringBuilder line = new StringBuilder(); + appendNParam(line, 1400, 4); + appendAParam(line, identifier, 4); + appendAParam(line, customer, 25); + appendAParam(line, description, 40); + appendAParam(line, accountNumber, 25); + appendAParam(line, settleAccountName, 30); + appendNParam(line, settleBSB, 6); + appendNParam(line, settleAccountNo, 30); + appendDParam(line, periodStart, 8); + appendDParam(line, periodEnd, 8); + appendAParam(line, currency, 3); + appendNParam(line, grossPayment.intValue(), 13); + appendNParam(line, transactionCount, 13); + appendNParam(line, totalRefund.intValue(), 13); + appendNParam(line, refundCount, 13); + appendNParam(line, cashoutAmount.intValue(), 13); + appendNParam(line, cashoutCount, 13); + appendNParam(line, cashoutComponentAmount.intValue(), 20); + appendFiller(line, 1119); + builder.append(line); + return builder; + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/analysis/core/ATOReportService.java b/src/main/java/au/com/royalpay/payment/manage/analysis/core/ATOReportService.java new file mode 100644 index 000000000..b1b018dcd --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/analysis/core/ATOReportService.java @@ -0,0 +1,11 @@ +package au.com.royalpay.payment.manage.analysis.core; + +import java.util.Date; + +/** + * Create by yixian at 2018-08-31 1:22 + */ +public interface ATOReportService { + + String exportBTTPSFile(Date from, Date to); +} diff --git a/src/main/java/au/com/royalpay/payment/manage/analysis/core/impls/ATOReportServiceImpl.java b/src/main/java/au/com/royalpay/payment/manage/analysis/core/impls/ATOReportServiceImpl.java new file mode 100644 index 000000000..5ecb72367 --- /dev/null +++ b/src/main/java/au/com/royalpay/payment/manage/analysis/core/impls/ATOReportServiceImpl.java @@ -0,0 +1,132 @@ +package au.com.royalpay.payment.manage.analysis.core.impls; + +import au.com.royalpay.payment.manage.analysis.beans.ato.*; +import au.com.royalpay.payment.manage.analysis.core.ATOReportService; +import au.com.royalpay.payment.manage.mappers.payment.TransactionMapper; +import au.com.royalpay.payment.manage.mappers.system.ClientMapper; +import au.com.royalpay.payment.tools.exceptions.ServerErrorException; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.codec.Charsets; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.time.DateFormatUtils; +import org.joda.time.DateTime; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Create by yixian at 2018-08-31 1:23 + */ +@Service +public class ATOReportServiceImpl implements ATOReportService { + private Logger logger = LoggerFactory.getLogger(getClass()); + @Resource + private TransactionMapper transactionMapper; + @Resource + private ClientMapper clientMapper; + @Value("classpath:data/category/billbuddyindustry.json") + private org.springframework.core.io.Resource industryResource; + private Map industryMap; + + @PostConstruct + public void loadIndustryConfiguration() throws IOException { + industryMap = new HashMap<>(); + JSONArray config = JSON.parseArray(IOUtils.toString(industryResource.getInputStream(), Charsets.UTF_8)); + for (int i = 0; i < config.size(); i++) { + JSONObject industry = config.getJSONObject(i); + loadIndustry(industry, null); + } + } + + private void loadIndustry(JSONObject industry, String parentCategory) { + JSONArray children = industry.getJSONArray("children"); + String category = industry.getString("category"); + String code = industry.getString("mccCode"); + if (category == null && parentCategory == null) { + throw new ServerErrorException("Industry Have No Category Code:" + code); + } + category = category == null ? parentCategory : category; + industryMap.put(code, category); + if (children != null && !children.isEmpty()) { + for (int i = 0; i < children.size(); i++) { + JSONObject subIndustry = children.getJSONObject(i); + loadIndustry(subIndustry, category); + } + } + } + + @Override + public String exportBTTPSFile(Date from, Date to) { + String reference = "RPAY" + DateFormatUtils.format(new Date(), "yyyyMMddHHmm"); + String abn = "16601619685"; + String registerCompanyName = "Tunnel Show Pty Ltd"; + AddressInfo companyAddr = new AddressInfo("Level 11, 15 William St", "Melbourne", "VIC", "3000", "AUS"); + ContactInfo companyContact = new ContactInfo("Locky", "+61394488865", "info@royalpay.com.au"); + ATOBulkData.IntermediaryData intermediary = new ATOBulkData.IntermediaryData(abn, registerCompanyName, reference) + .setAddress(companyAddr) + .setContactInfo(companyContact); + ATOBulkData data = new ATOBulkData(intermediary); + + ReportingPartyData reportingParty = new ReportingPartyData(from, to, abn, "001", registerCompanyName, "INHOUSE Tunnel Show") + .setAddress(companyAddr) + .setPostalAddress(companyAddr) + .setContactInfo(companyContact) + .setTradingName("RoyalPay"); + intermediary.addReportingParty(reportingParty); + + DateTime fromDateTime = new DateTime(from).withTimeAtStartOfDay(); + DateTime toDateTime = new DateTime(to).plusDays(1).withTimeAtStartOfDay(); + DateTime startOfMon = new DateTime(fromDateTime); + DateTime endOfMon = new DateTime(fromDateTime.plusMonths(1).withDayOfMonth(1)); + while (endOfMon.isBefore(toDateTime)) { + logger.debug("Exporting date range:" + startOfMon.toString("yyyy-MM-dd") + " ~ " + endOfMon.toString("yyyy-MM-dd")); + loadMonthTransactions(reportingParty, startOfMon, endOfMon); + startOfMon = new DateTime(endOfMon); + endOfMon = new DateTime(endOfMon.plusMonths(1)); + } + endOfMon = new DateTime(toDateTime); + logger.debug("Exporting date range:" + startOfMon.toString("yyyy-MM-dd") + " ~ " + endOfMon.toString("yyyy-MM-dd")); + loadMonthTransactions(reportingParty, startOfMon, endOfMon); + logger.info("output BTTPS file"); + return data.outputBTTPS(); + } + + private void loadMonthTransactions(ReportingPartyData reportingParty, DateTime startOfMon, DateTime endOfMon) { + List clients = clientMapper.listClientsWithTransactionsSettled(startOfMon.toDate(), endOfMon.toDate()); + clients.parallelStream().forEach(clientId -> loadClientMonthTransactions(reportingParty, clientId, startOfMon, endOfMon)); + } + + private void loadClientMonthTransactions(ReportingPartyData reportingParty, Integer clientId, DateTime startOfMon, DateTime endOfMon) { + BusinessData biz = reportingParty.findBusiness(clientId); + logger.debug("Exporting date range for client[" + clientId + "]:" + startOfMon.toString("yyyy-MM-dd") + " ~ " + endOfMon.toString("yyyy-MM-dd")); + if (biz == null) { + JSONObject cli = clientMapper.findClientIgnoreInvalid(clientId); + AddressInfo addr = new AddressInfo(cli.getString("address"), cli.getString("suburb"), cli.getString("state"), cli.getString("postcode"), cli.getString("country")); + ContactInfo contact = new ContactInfo(cli.getString("contact_person"), cli.getString("contact_phone"), cli.getString("contact_email")); + String industry = industryMap.getOrDefault(cli.getString("royalpayindustry"), cli.getString("royalpayindustry")); + String clientMoniker = cli.getString("client_moniker"); + biz = new BusinessData(cli.getDate("create_time"), cli.getString("abn"), cli.getString("acn"), + cli.getString("company_name"), cli.getString("short_name"), clientMoniker, + industry, "O") + .setAddress(addr) + .setPostalAddress(addr) + .setContactInfo(contact); + reportingParty.addBusiness(clientId, biz); + } + List analysisList = transactionMapper.analysisForATOReport(clientId, startOfMon.toDate(), endOfMon.toDate()); + for (JSONObject analysis : analysisList) { + biz.addTransaction(new TransactionSummaryData(analysis, startOfMon, endOfMon)); + } + } +} diff --git a/src/main/java/au/com/royalpay/payment/manage/dev/web/TestController.java b/src/main/java/au/com/royalpay/payment/manage/dev/web/TestController.java index dfbeebe28..c14326cc6 100644 --- a/src/main/java/au/com/royalpay/payment/manage/dev/web/TestController.java +++ b/src/main/java/au/com/royalpay/payment/manage/dev/web/TestController.java @@ -34,6 +34,7 @@ import au.com.royalpay.payment.tools.utils.XmlFormatUtils; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.SerializerFeature; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.DateFormatUtils; import org.dom4j.Element; import org.slf4j.Logger; @@ -245,7 +246,8 @@ public class TestController implements ApplicationEventPublisherAware { List orders = orderMapper.listOrdersWithNoTransactions(); for (JSONObject order : orders) { try { - paymentApi.checkOrderStatus(order.getString("order_id"), order.getString("channel"), true); + String orderChannel = StringUtils.defaultIfEmpty(order.getString("order_channel"), order.getString("channel")); + paymentApi.checkOrderStatus(order.getString("order_id"), orderChannel, true); } catch (Exception e) { logger.error("fix transaction error:" + order.getString("order_id")); } @@ -262,7 +264,7 @@ public class TestController implements ApplicationEventPublisherAware { if (order == null) { throw new OrderNotExistsException(); } - String channel = order.getString("channel"); + String channel = StringUtils.defaultIfEmpty(order.getString("order_channel"), order.getString("channel")); JSONObject res = new JSONObject(); switch (channel) { case "Wechat": @@ -286,7 +288,7 @@ public class TestController implements ApplicationEventPublisherAware { res.put("xml", xmlStr); break; case "AlipayOnline": - elem = alipayClient.checkOnlineOrderStatusByOrderId(orderId,AlipayEnvironment.getEnv().getAlipayOnlineMerchant().getPid()); + elem = alipayClient.checkOnlineOrderStatusByOrderId(orderId, AlipayEnvironment.getEnv().getAlipayOnlineMerchant().getPid()); xmlStr = XmlFormatUtils.formatXml(elem); res.put("xml", xmlStr); break; @@ -315,7 +317,7 @@ public class TestController implements ApplicationEventPublisherAware { res.put("xml", xml); break; case "Alipay": - elem = alipayClient.retailRefund(type, refundOrder.getBigDecimal("refund_exchange_rate"), refundOrder,AlipayEnvironment.getEnv().getAlipayRetailMerchant().getPid()); + elem = alipayClient.retailRefund(type, refundOrder.getBigDecimal("refund_exchange_rate"), refundOrder, AlipayEnvironment.getEnv().getAlipayRetailMerchant().getPid()); String xmlStr = XmlFormatUtils.formatXml(elem); res.put("xml", xmlStr); break; @@ -330,7 +332,7 @@ public class TestController implements ApplicationEventPublisherAware { res.put("xml", xmlStr); break; case "AlipayOnline": - elem = alipayClient.onlineRefund(refundOrder,AlipayEnvironment.getEnv().getAlipayOnlineMerchant().getPid(), type == TradeType.GATEWAY_H5); + elem = alipayClient.onlineRefund(refundOrder, AlipayEnvironment.getEnv().getAlipayOnlineMerchant().getPid(), type == TradeType.GATEWAY_H5); xmlStr = XmlFormatUtils.formatXml(elem); res.put("xml", xmlStr); break; @@ -389,12 +391,12 @@ public class TestController implements ApplicationEventPublisherAware { @ManagerMapping(value = "/aliforexcel", method = RequestMethod.GET, role = ManagerRole.DEVELOPER) public void aliforexcel(@ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager, HttpServletResponse httpResponse, AliExcel query) throws Exception { - aliforexcelService.listClients(httpResponse,manager,query); + aliforexcelService.listClients(httpResponse, manager, query); } @ManagerMapping(value = "/hfClearAmount", method = RequestMethod.GET, role = ManagerRole.DEVELOPER) public JSONObject hfUpdate(@RequestParam String datefrom, @RequestParam String dateto) { - return hfClearAmountService.hfjsonobject(dateto,datefrom); + return hfClearAmountService.hfjsonobject(dateto, datefrom); } @ManagerMapping(value = "/hfUpdate", method = RequestMethod.GET, role = ManagerRole.DEVELOPER) diff --git a/src/main/java/au/com/royalpay/payment/manage/mappers/payment/TransactionMapper.java b/src/main/java/au/com/royalpay/payment/manage/mappers/payment/TransactionMapper.java index 8cebfdf09..d2b2a2dac 100644 --- a/src/main/java/au/com/royalpay/payment/manage/mappers/payment/TransactionMapper.java +++ b/src/main/java/au/com/royalpay/payment/manage/mappers/payment/TransactionMapper.java @@ -8,6 +8,7 @@ import com.alibaba.fastjson.JSONObject; import com.github.miemiedev.mybatis.paginator.domain.PageBounds; import com.github.miemiedev.mybatis.paginator.domain.PageList; import org.apache.ibatis.annotations.Param; +import org.joda.time.DateTime; import java.math.BigDecimal; import java.util.Date; @@ -142,4 +143,6 @@ public interface TransactionMapper { void removeSettleRemark(@Param("clearing_id") int clearingId); List getHfClearAmount(JSONObject params); + + List analysisForATOReport(@Param("clientId") int clientId, @Param("from") Date startOfMon, @Param("to") Date endOfMon); } diff --git a/src/main/java/au/com/royalpay/payment/manage/mappers/system/ClientMapper.java b/src/main/java/au/com/royalpay/payment/manage/mappers/system/ClientMapper.java index 281ef65c3..da095448a 100644 --- a/src/main/java/au/com/royalpay/payment/manage/mappers/system/ClientMapper.java +++ b/src/main/java/au/com/royalpay/payment/manage/mappers/system/ClientMapper.java @@ -83,6 +83,8 @@ public interface ClientMapper { List listBySubMerchantId(@Param("sub_merchant_id") String sub_merchant_id); + List listClientsWithTransactionsSettled(@Param("from") Date fromDate, @Param("to") Date toDate); + @AutoSql(type = SqlType.SELECT) List AllClients(); diff --git a/src/main/resources/au/com/royalpay/payment/manage/mappers/payment/TransactionMapper.xml b/src/main/resources/au/com/royalpay/payment/manage/mappers/payment/TransactionMapper.xml index cefdfcfad..7886a2c6a 100644 --- a/src/main/resources/au/com/royalpay/payment/manage/mappers/payment/TransactionMapper.xml +++ b/src/main/resources/au/com/royalpay/payment/manage/mappers/payment/TransactionMapper.xml @@ -101,13 +101,17 @@ - + SELECT ifnull(sum(if(transaction_type = 'Credit', clearing_amount, -clearing_amount)), 0) + clearing_amount,client_id FROM pmt_transactions - where clearing_status = 0 AND + where clearing_status = 0 AND client_id in - - #{item} - - group by client_id + + #{item} + + group by client_id @@ -420,6 +429,8 @@ temp.create_time) and d.bd_id=#{bd_id} -]]> + + + ]]> @@ -554,6 +579,8 @@ select sum(if(temp.transaction_type='Credit',temp.clearing_amount*d.proportion, @@ -623,6 +652,8 @@ select sum(if(temp.transaction_type='Credit',temp.clearing_amount*d.proportion, + \ No newline at end of file diff --git a/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientMapper.xml b/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientMapper.xml index 64cf17945..8e78618fb 100644 --- a/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientMapper.xml +++ b/src/main/resources/au/com/royalpay/payment/manage/mappers/system/ClientMapper.xml @@ -272,14 +272,12 @@ @@ -358,6 +356,11 @@ and contact_email = #{contact_email} +