diff --git a/pom.xml b/pom.xml index a559b6ef2..c3cfc1b87 100644 --- a/pom.xml +++ b/pom.xml @@ -5,14 +5,14 @@ au.com.royalpay.payment payment-parent - 2.1.48 + 2.1.49 4.0.0 manage - 2.3.8 + 2.3.10 UTF-8 - 2.2.0 + 2.3.0 ${project.version} @@ -203,6 +203,28 @@ org.projectlombok lombok + + + com.itextpdf + itextpdf + 5.5.13 + + + com.itextpdf.tool + xmlworker + 5.5.13 + + + com.itextpdf + itext-asian + 5.2.0 + + + org.xhtmlrenderer + flying-saucer-pdf + 9.0.3 + + diff --git a/src/document/openapi/cn/document.yml b/src/document/openapi/cn/document.yml index b77863011..ac99dd9d4 100644 --- a/src/document/openapi/cn/document.yml +++ b/src/document/openapi/cn/document.yml @@ -555,6 +555,10 @@ paths: type: boolean default: false description: 如果希望禁止消费者使用信用卡支付可传入true + disable_threeds: + type: boolean + default: false + description: 平台会协助商户自动开启3DS校验以减少盗刷风险。如果商户希望关闭这个功能,可以提交当前参数为true。(3DS校验需要消费者多一步银行端验证,并且如小程序等场景无法实现网页跳转到银行页面导致流程无法继续) tokenize: type: boolean default: false @@ -669,6 +673,10 @@ paths: type: boolean default: false description: 如果希望禁止消费者使用信用卡支付可传入true + disable_threeds: + type: boolean + default: false + description: 平台会协助商户自动开启3DS校验以减少盗刷风险。如果商户希望关闭这个功能,可以提交当前参数为true。(3DS校验需要消费者多一步银行端验证,并且如小程序等场景无法实现网页跳转到银行页面导致流程无法继续) customer: $ref: 'components_order.yml#/cardCustomerParam' responses: @@ -677,7 +685,13 @@ paths: content: application/json: schema: - $ref: 'components_order.yml#/orderBasicResponse' + allOf: + - $ref: 'components_order.yml#/orderBasicResponse' + - type: object + properties: + pay_url: + type: string + description: 当开启3DS校验时系统会返回当前参数,商户应该引导消费者跳转到此页面完成3DS认证 /micropay/partners/{partner_code}/orders/{partner_order_id}: put: summary: 付款码下单 diff --git a/src/document/openapi/en/document.yml b/src/document/openapi/en/document.yml index 56b998930..09e5846c4 100644 --- a/src/document/openapi/en/document.yml +++ b/src/document/openapi/en/document.yml @@ -568,6 +568,10 @@ paths: type: boolean default: false description: pass true if merchant want to disable credit cards from paying to this order. + disable_threeds: + type: boolean + default: false + description: We will help merchants to enable 3DS verify by default. If you want to disable this feature please set this parameter as true tokenize: type: boolean default: false @@ -619,7 +623,7 @@ paths: put: summary: Create Card Order description: | - Input https://channel.rpayplus.com/channel/v1/view/card_input_frame.js in merchant's webpage. + Input https://channel-gateway.royalpay.com.au/channel/v1/view/card_input_frame.js in merchant's webpage. After called commit, it will return `key_id` and `secret` parameter asyncronized by callback. Post these parameter to royalpay and finish payment directly. @@ -690,6 +694,10 @@ paths: type: boolean default: false description: Pass true if want to refuse credit cards. + disable_threeds: + type: boolean + default: false + description: We will help merchants to enable 3DS verify by default. If you want to disable this feature please set this parameter as true customer: $ref: 'components_order.yml#/cardCustomerParam' responses: @@ -698,7 +706,13 @@ paths: content: application/json: schema: - $ref: 'components_order.yml#/orderBasicResponse' + allOf: + - $ref: 'components_order.yml#/orderBasicResponse' + - type: object + properties: + pay_url: + type: string + description: If order requires 3DS verify. it will return this parameter. Merchants's system should guide customer to redirect to this url and finish 3DS verify. Remember to add signatures and return_url param /micropay/partners/{partner_code}/orders/{partner_order_id}: put: summary: Retail Passive Payment Order 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 7f9cffde7..8007500ac 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 @@ -26,6 +26,7 @@ import au.com.royalpay.payment.manage.merchants.core.ClientManager; import au.com.royalpay.payment.manage.permission.manager.ManagerMapping; import au.com.royalpay.payment.manage.pos.datasource.ReadOnlyConnection; import au.com.royalpay.payment.manage.system.core.TradeSecureService; +import au.com.royalpay.payment.manage.tradelog.beans.TradeLogQuery; import au.com.royalpay.payment.manage.tradelog.core.TradeLogService; import au.com.royalpay.payment.tools.CommonConsts; import au.com.royalpay.payment.tools.connections.mpsupport.MpWechatApi; @@ -52,6 +53,7 @@ import org.joda.time.DateTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; +import org.springframework.ui.Model; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.util.Assert; import org.springframework.util.MimeTypeUtils; @@ -556,4 +558,22 @@ public class TestController { model.addObject("client", result); return model; } + + @GetMapping(value = "/trans_flow/pdf") + @ReadOnlyConnection + public ModelAndView exportTransFlowPDFHtml(TradeLogQuery query, @RequestParam String client_moniker, Model model) throws Exception { + return tradeLogService.exportTransFlow(query, getPartnerParams(client_moniker), model); + } + + private JSONObject getPartnerParams(String clientMoniker) { + JSONObject client = clientManager.getClientInfoByMoniker(clientMoniker); + if (client == null) { + throw new NotFoundException("Client Not Exists"); + } + JSONObject params = new JSONObject(); + params.put("client_id", client.getIntValue("client_id")); + params.put("client", client); + params.put("client_moniker", clientMoniker); + return params; + } } 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 518998db4..a722db989 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 @@ -1,13 +1,13 @@ package au.com.royalpay.payment.manage.mappers.payment; +import com.alibaba.fastjson.JSONObject; +import com.github.miemiedev.mybatis.paginator.domain.PageBounds; +import com.github.miemiedev.mybatis.paginator.domain.PageList; import com.yixsoft.support.mybatis.autosql.annotations.AdvanceSelect; import com.yixsoft.support.mybatis.autosql.annotations.AutoMapper; import com.yixsoft.support.mybatis.autosql.annotations.AutoSql; import com.yixsoft.support.mybatis.autosql.annotations.SqlType; import com.yixsoft.support.mybatis.paginator.annotations.CountRef; -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.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; @@ -20,8 +20,6 @@ import java.util.List; */ @AutoMapper(tablename = "pmt_transactions", pkName = "transaction_id", keyGenerator = Jdbc3KeyGenerator.class) public interface TransactionMapper { - @AutoSql(SqlType.INSERT) - void save(JSONObject transaction); PageList listTransFlowPage(JSONObject params, PageBounds pagination); @@ -37,9 +35,6 @@ public interface TransactionMapper { @AdvanceSelect(addonWhereClause = "transaction_type = 'Credit'") JSONObject findByOrderId(@Param("order_id") String orderId); - @AutoSql(SqlType.UPDATE) - void update(JSONObject transaction); - JSONObject findLastIncome(); double getClientUnClearedAmount(@Param("client_id") int clientId); diff --git a/src/main/java/au/com/royalpay/payment/manage/pos/datasource/ReadOnlyConnectionInterceptor.java b/src/main/java/au/com/royalpay/payment/manage/pos/datasource/ReadOnlyConnectionInterceptor.java index eaa04b71a..1ac0a8b4b 100644 --- a/src/main/java/au/com/royalpay/payment/manage/pos/datasource/ReadOnlyConnectionInterceptor.java +++ b/src/main/java/au/com/royalpay/payment/manage/pos/datasource/ReadOnlyConnectionInterceptor.java @@ -19,8 +19,7 @@ public class ReadOnlyConnectionInterceptor implements Ordered { public Object proceed(ProceedingJoinPoint proceedingJoinPoint, ReadOnlyConnection readOnlyConnection) throws Throwable { try { DbContextHolder.setDbType(DbContextHolder.DbType.SLAVE); - Object result = proceedingJoinPoint.proceed(); - return result; + return proceedingJoinPoint.proceed(); } finally { DbContextHolder.clearDbType(); } diff --git a/src/main/java/au/com/royalpay/payment/manage/tradelog/core/TradeLogService.java b/src/main/java/au/com/royalpay/payment/manage/tradelog/core/TradeLogService.java index a9e3a978a..7dcf8e398 100644 --- a/src/main/java/au/com/royalpay/payment/manage/tradelog/core/TradeLogService.java +++ b/src/main/java/au/com/royalpay/payment/manage/tradelog/core/TradeLogService.java @@ -4,6 +4,7 @@ import au.com.royalpay.payment.manage.tradelog.beans.PreRefundQueryBean; import au.com.royalpay.payment.manage.tradelog.beans.TradeLogQuery; import com.alibaba.fastjson.JSONObject; import org.springframework.ui.Model; +import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletResponse; import java.util.List; @@ -36,6 +37,8 @@ public interface TradeLogService { void exportTransFlow(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws Exception; + ModelAndView exportTransFlow(TradeLogQuery query, JSONObject partner, Model model) throws Exception; + void exportUpayTransFlow(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws Exception; void exportTransFlowApi(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws Exception; diff --git a/src/main/java/au/com/royalpay/payment/manage/tradelog/core/impls/TradeLogServiceImpl.java b/src/main/java/au/com/royalpay/payment/manage/tradelog/core/impls/TradeLogServiceImpl.java index 6679d26c9..08d6f8583 100644 --- a/src/main/java/au/com/royalpay/payment/manage/tradelog/core/impls/TradeLogServiceImpl.java +++ b/src/main/java/au/com/royalpay/payment/manage/tradelog/core/impls/TradeLogServiceImpl.java @@ -61,6 +61,10 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.ui.Model; +import org.springframework.web.servlet.ModelAndView; +import org.thymeleaf.context.Context; +import org.thymeleaf.spring5.SpringTemplateEngine; +import org.xhtmlrenderer.pdf.ITextRenderer; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; @@ -127,6 +131,9 @@ public class TradeLogServiceImpl implements TradeLogService { @Resource private Locker locker; + @Resource + private SpringTemplateEngine thymeleaf; + // @Value("classpath:/jasper/trans_flow.jasper") // @Value("classpath:/jasper/trans_flow_new.jasper") @Value("classpath:/jasper/partner_invoice_gst.jasper") @@ -515,9 +522,6 @@ public class TradeLogServiceImpl implements TradeLogService { params.put("client_id", client_id); JSONObject mchConfig = merchantInfoProvider.getMchExtParams(partner.getIntValue("client_id")); params.put("hide_sub_mch", mchConfig.getBooleanValue("hide_sub_mch")); - -// PageList logs = transactionMapper.listTransFlowPage(params, -// new PageBounds(query.getPage(), query.getLimit(), Order.formString("transaction_time.desc"))); List logs = transactionMapper.listTransFlow(params); TimeZoneUtils.switchTimeZone(logs, timezone, "create_time", "confirm_time", "transaction_time"); Paginator paginator = new Paginator(query.getPage(), query.getLimit(), logs.size()); @@ -562,9 +566,11 @@ public class TradeLogServiceImpl implements TradeLogService { int clientId = partner.getIntValue("client_id"); String timezone = partner.getJSONObject("client").getString("timezone"); JSONObject params = query.toParams(timezone); - params.put("channel", channels); +// params.put("channel", channels); clientManager.validateClients(clientId, params); params.put("client_id", clientId); + JSONObject mchConfig = merchantInfoProvider.getMchExtParams(partner.getIntValue("client_id")); + params.put("hide_sub_mch", mchConfig.getBooleanValue("hide_sub_mch")); clientManager.queryModifyClientIds(clientId, params); List logs = transactionMapper.listTransFlow(params); TimeZoneUtils.switchTimeZoneToString(logs, timezone, "dd/MM/yyyy HH:mm:ss", Collections.singletonList("transaction_time")); @@ -687,13 +693,90 @@ public class TradeLogServiceImpl implements TradeLogService { return "Credit".equals(log.getString("transaction_type")) || "Settlement".equals(log.getString("channel")) ? BigDecimal.ONE : BigDecimal.valueOf(-1); } + // @Override +// public void exportTransFlow(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws Exception { +// JSONObject transFlow = listPartnerTransFlow(query, partner); +// JSONObject analysis = transFlow.getJSONObject("analysis"); +// JSONObject client = clientManager.getClientInfo(partner.getIntValue("client_id")); +// if (!transFlow.getJSONArray("data").isEmpty()) { +// try { +// List dataList = transFlow.getJSONArray("data").toJavaList(JSONObject.class); +// JSONObject parmerters = new JSONObject(); +// parmerters.put("dateFrom", StringUtils.isNotBlank(query.getDatefrom()) +// ? DateFormatUtils.format(DateUtils.parseDate(query.getDatefrom(), "yyyyMMdd"), "dd/MM/yyyy") : ""); +// parmerters.put("dateTo", +// StringUtils.isNotBlank(query.getDateto()) +// ? DateFormatUtils.format(DateUtils.parseDate(query.getDateto(), "yyyyMMdd"), "dd/MM/yyyy") +// : DateFormatUtils.format(new Date(), "dd/MM/yyyy")); +// parmerters.put("dateRange", (StringUtils.isNotBlank(parmerters.getString("dateFrom")) ? parmerters.getString("dateFrom") : "") + "~" +// + parmerters.getString("dateTo")); +// parmerters.put("partnerCode", client.getString("client_moniker")); +// parmerters.put("clientName", client.getString("company_name")); +// parmerters.put("clientAddress", client.getString("address")); +// parmerters.put("balance", analysis.getDoubleValue("balance")); +// parmerters.put("logo", logo.getInputStream()); +// parmerters.put("actual_fee", takeDecimalOrDefault(analysis, "actual_fee", BigDecimal.ZERO)); +// parmerters.put("totalSettledAmount", takeDecimalOrDefault(analysis, "total_settle_amount", BigDecimal.ZERO)); +// parmerters.put("royalpay_charge", takeDecimalOrDefault(analysis, "total_royal_surcharge", BigDecimal.ZERO)); +// parmerters.put("total_fee", takeDecimalOrDefault(analysis, "total_surcharge", BigDecimal.ZERO)); +// parmerters.put("alipay_fee", takeDecimalOrDefault(analysis, "alipay_fee", BigDecimal.ZERO)); +// parmerters.put("wechat_fee", takeDecimalOrDefault(analysis, "wechat_fee", BigDecimal.ZERO)); +// parmerters.put("bestpay_fee", takeDecimalOrDefault(analysis, "bestpay_fee", BigDecimal.ZERO)); +// parmerters.put("jd_fee", takeDecimalOrDefault(analysis, "jd_fee", BigDecimal.ZERO)); +// parmerters.put("alipay_online_fee", takeDecimalOrDefault(analysis, "alipay_online_fee", BigDecimal.ZERO)); +// parmerters.put("gst", takeDecimalOrDefault(analysis, "tax_amount", BigDecimal.ZERO)); +// parmerters.put("royalpay_fee", takeDecimalOrDefault(analysis, "total_royalpay_fee", BigDecimal.ZERO)); +// parmerters.put("incremental_fee", takeDecimalOrDefault(analysis, "total_incremental_surcharge", BigDecimal.ZERO)); +// parmerters.put("incremental_gst", takeDecimalOrDefault(analysis, "total_incremental_tax", BigDecimal.ZERO)); +// parmerters.put("royalpay_gst", analysis.getBigDecimal("tax_amount").subtract(analysis.getBigDecimal("total_incremental_tax")).setScale(2,RoundingMode.HALF_UP)); +// +// dataList.parallelStream().forEach(item -> { +// BigDecimal incrementalSurcharge = item.containsKey("incremental_surcharge") ? item.getBigDecimal("incremental_surcharge") : BigDecimal.ZERO; +// BigDecimal taxAmount = item.containsKey("tax_amount") ? item.getBigDecimal("tax_amount") : BigDecimal.ZERO; +// BigDecimal royalpaySurhcarge = item.containsKey("royal_surcharge") ? item.getBigDecimal("royal_surcharge") : BigDecimal.ZERO; +// BigDecimal surhcargeBack = item.containsKey("surcharge_cashback") ? item.getBigDecimal("surcharge_cashback") : BigDecimal.ZERO; +// BigDecimal channelSurcharge = item.containsKey("channel_surcharge") ? item.getBigDecimal("channel_surcharge") : BigDecimal.ZERO; +// BigDecimal incrementalTax = incrementalSurcharge.divide(new BigDecimal(10), 2, RoundingMode.HALF_UP); +// BigDecimal royalpayTax = taxAmount.subtract(incrementalTax); +// BigDecimal realRoyalpayCharge = royalpaySurhcarge +// .add(surhcargeBack) +// .add(channelSurcharge) +// .add(royalpayTax); +// item.put("incremental_surcharge", incrementalSurcharge.add(incrementalTax).setScale(2, RoundingMode.HALF_UP)); +// item.put("real_royalpay_surcharge", realRoyalpayCharge.setScale(2, RoundingMode.HALF_UP)); +// scaleDecimalVal(item, "display_amount", item.getString("currency")); +// String platformCurrency = PlatformEnvironment.getEnv().getForeignCurrency(); +// scaleDecimalVal(item, "clearing_amount", platformCurrency); +// scaleDecimalVal(item, "settle_amount", platformCurrency); +// scaleDecimalVal(item, "total_surcharge", platformCurrency); +// }); +// JRDataSource jrDataSource = new JRBeanCollectionDataSource(dataList); +// response.setContentType("application/pdf"); +// String fileName = client.getString("client_moniker") + "_" + parmerters.getString("dateRange").replaceAll("/", ""); +// response.setHeader("Content-Disposition", "attachment;fileName=" + fileName + ".pdf"); +// OutputStream outs = response.getOutputStream(); +// JSONObject clientIncrement = clientIncrementalMapper.findByClinetIdAndChannel(client.getIntValue("client_id"), "RP跨境商城"); +// InputStream jasper = clientIncrement == null ? trans_flow.getInputStream() : incremental_trans_flow.getInputStream(); +// byte[] bytes = JasperRunManager.runReportToPdf(jasper, parmerters, jrDataSource); +// outs.write(bytes, 0, bytes.length); +// outs.flush(); +// outs.close(); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// +// } +// } @Override public void exportTransFlow(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws Exception { - JSONObject transFlow = listPartnerTransFlowByExportPdf(query, partner,new String[]{"Wechat","Alipay","AlipayOnline"}); + JSONObject transFlow = listPartnerTransFlowByExportPdf(query, partner, new String[]{"Wechat", "Alipay", "AlipayOnline"}); JSONObject analysis = transFlow.getJSONObject("analysis"); JSONObject client = clientManager.getClientInfo(partner.getIntValue("client_id")); + Context ctx = new Context(); if (!transFlow.getJSONArray("data").isEmpty()) { - try { + try (OutputStream outs = response.getOutputStream(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ) { List dataList = transFlow.getJSONArray("data").toJavaList(JSONObject.class); JSONObject parmerters = new JSONObject(); parmerters.put("dateFrom", StringUtils.isNotBlank(query.getDatefrom()) @@ -702,7 +785,7 @@ public class TradeLogServiceImpl implements TradeLogService { StringUtils.isNotBlank(query.getDateto()) ? DateFormatUtils.format(DateUtils.parseDate(query.getDateto(), "yyyyMMdd"), "dd/MM/yyyy") : DateFormatUtils.format(new Date(), "dd/MM/yyyy")); - parmerters.put("dateRange", (StringUtils.isNotBlank(parmerters.getString("dateFrom")) ? parmerters.getString("dateFrom") : "") + "~" + parmerters.put("dateRange", (StringUtils.isNotBlank(parmerters.getString("dateFrom")) ? parmerters.getString("dateFrom") : "") + " ~ " + parmerters.getString("dateTo")); parmerters.put("partnerCode", client.getString("client_moniker")); parmerters.put("clientName", client.getString("company_name")); @@ -720,7 +803,7 @@ public class TradeLogServiceImpl implements TradeLogService { parmerters.put("royalpay_fee", takeDecimalOrDefault(analysis, "total_royalpay_fee", BigDecimal.ZERO)); parmerters.put("incremental_fee", takeDecimalOrDefault(analysis, "total_incremental_surcharge", BigDecimal.ZERO)); parmerters.put("incremental_gst", takeDecimalOrDefault(analysis, "total_incremental_tax", BigDecimal.ZERO)); - parmerters.put("royalpay_gst", analysis.getBigDecimal("tax_amount").subtract(analysis.getBigDecimal("total_incremental_tax")).setScale(2,RoundingMode.HALF_UP)); + parmerters.put("royalpay_gst", analysis.getBigDecimal("tax_amount").subtract(analysis.getBigDecimal("total_incremental_tax")).setScale(2, RoundingMode.HALF_UP)); dataList.parallelStream().forEach(item -> { BigDecimal incrementalSurcharge = item.containsKey("incremental_surcharge") ? item.getBigDecimal("incremental_surcharge") : BigDecimal.ZERO; @@ -741,18 +824,34 @@ public class TradeLogServiceImpl implements TradeLogService { scaleDecimalVal(item, "clearing_amount", platformCurrency); scaleDecimalVal(item, "settle_amount", platformCurrency); scaleDecimalVal(item, "total_surcharge", platformCurrency); + String debit = item.getString("transaction_type").equals("Debit") ? item.getBigDecimal("clearing_amount").toString() + : "-"; + String credit = item.getString("transaction_type").equals("Credit") ? item.getBigDecimal("clearing_amount").toString() + : "-"; + item.put("debit", debit); + item.put("credit", credit); + item.putIfAbsent("settle_amount", "-"); }); - JRDataSource jrDataSource = new JRBeanCollectionDataSource(dataList); + ctx.setVariable("parmerters", parmerters); + ctx.setVariable("dataList", dataList); + JSONObject orgInfo = orgManager.getOrgDetail(client.getIntValue("org_id"), null); + if (!orgInfo.containsKey("logo") || orgInfo.getIntValue("org_id") == 1) { + orgInfo.put("logo", "none"); + } + ctx.setVariable("orgInfo", orgInfo); + final String html = thymeleaf.process("app/invoice.html", ctx); response.setContentType("application/pdf"); String fileName = client.getString("client_moniker") + "_Cross_Border_" + parmerters.getString("dateRange").replaceAll("/", ""); response.setHeader("Content-Disposition", "attachment;fileName=" + fileName + ".pdf"); - OutputStream outs = response.getOutputStream(); - JSONObject clientIncrement = clientIncrementalMapper.findByClinetIdAndChannel(client.getIntValue("client_id"), "RP跨境商城"); - InputStream jasper = clientIncrement == null ? trans_flow.getInputStream() : incremental_trans_flow.getInputStream(); - byte[] bytes = JasperRunManager.runReportToPdf(jasper, parmerters, jrDataSource); + ITextRenderer renderer = new ITextRenderer(); + //添加字体库end + renderer.setDocumentFromString(html); + renderer.layout(); + renderer.createPDF(os); + byte[] bytes = os.toByteArray(); outs.write(bytes, 0, bytes.length); outs.flush(); - outs.close(); + renderer.finishPDF(); } catch (Exception e) { e.printStackTrace(); } @@ -761,8 +860,86 @@ public class TradeLogServiceImpl implements TradeLogService { } @Override - public void exportUpayTransFlow(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws Exception { - JSONObject transFlow = listPartnerTransFlowByExportPdf(query, partner,new String[]{"rpaypmt_card","rpaypmt_dd"}); + public ModelAndView exportTransFlow(TradeLogQuery query, JSONObject partner, Model model) throws Exception { + JSONObject transFlow = listPartnerTransFlowByExportPdf(query, partner, new String[]{"Wechat", "Alipay", "AlipayOnline"}); + JSONObject analysis = transFlow.getJSONObject("analysis"); + JSONObject client = clientManager.getClientInfo(partner.getIntValue("client_id")); + ModelAndView view = new ModelAndView("app/invoice.html"); + if (!transFlow.getJSONArray("data").isEmpty()) { + try { + List dataList = transFlow.getJSONArray("data").toJavaList(JSONObject.class); + JSONObject parmerters = new JSONObject(); + parmerters.put("dateFrom", StringUtils.isNotBlank(query.getDatefrom()) + ? DateFormatUtils.format(DateUtils.parseDate(query.getDatefrom(), "yyyyMMdd"), "dd/MM/yyyy") : ""); + parmerters.put("dateTo", + StringUtils.isNotBlank(query.getDateto()) + ? DateFormatUtils.format(DateUtils.parseDate(query.getDateto(), "yyyyMMdd"), "dd/MM/yyyy") + : DateFormatUtils.format(new Date(), "dd/MM/yyyy")); + parmerters.put("dateRange", (StringUtils.isNotBlank(parmerters.getString("dateFrom")) ? parmerters.getString("dateFrom") : "") + " ~ " + + parmerters.getString("dateTo")); + parmerters.put("partnerCode", client.getString("client_moniker")); + parmerters.put("clientName", client.getString("company_name")); + parmerters.put("clientAddress", client.getString("address")); + parmerters.put("balance", analysis.getDoubleValue("balance")); + parmerters.put("logo", logo.getInputStream()); + parmerters.put("actual_fee", takeDecimalOrDefault(analysis, "actual_fee", BigDecimal.ZERO)); + parmerters.put("totalSettledAmount", takeDecimalOrDefault(analysis, "total_settle_amount", BigDecimal.ZERO)); + parmerters.put("royalpay_charge", takeDecimalOrDefault(analysis, "total_royal_surcharge", BigDecimal.ZERO)); + parmerters.put("total_fee", takeDecimalOrDefault(analysis, "total_surcharge", BigDecimal.ZERO)); + parmerters.put("alipay_fee", takeDecimalOrDefault(analysis, "alipay_fee", BigDecimal.ZERO)); + parmerters.put("wechat_fee", takeDecimalOrDefault(analysis, "wechat_fee", BigDecimal.ZERO)); + parmerters.put("alipay_online_fee", takeDecimalOrDefault(analysis, "alipay_online_fee", BigDecimal.ZERO)); + parmerters.put("gst", takeDecimalOrDefault(analysis, "tax_amount", BigDecimal.ZERO)); + parmerters.put("royalpay_fee", takeDecimalOrDefault(analysis, "total_royalpay_fee", BigDecimal.ZERO)); + parmerters.put("incremental_fee", takeDecimalOrDefault(analysis, "total_incremental_surcharge", BigDecimal.ZERO)); + parmerters.put("incremental_gst", takeDecimalOrDefault(analysis, "total_incremental_tax", BigDecimal.ZERO)); + parmerters.put("royalpay_gst", analysis.getBigDecimal("tax_amount").subtract(analysis.getBigDecimal("total_incremental_tax")).setScale(2, RoundingMode.HALF_UP)); + + dataList.parallelStream().forEach(item -> { + BigDecimal incrementalSurcharge = item.containsKey("incremental_surcharge") ? item.getBigDecimal("incremental_surcharge") : BigDecimal.ZERO; + BigDecimal taxAmount = item.containsKey("tax_amount") ? item.getBigDecimal("tax_amount") : BigDecimal.ZERO; + BigDecimal royalpaySurhcarge = item.containsKey("royal_surcharge") ? item.getBigDecimal("royal_surcharge") : BigDecimal.ZERO; + BigDecimal surhcargeBack = item.containsKey("surcharge_cashback") ? item.getBigDecimal("surcharge_cashback") : BigDecimal.ZERO; + BigDecimal channelSurcharge = item.containsKey("channel_surcharge") ? item.getBigDecimal("channel_surcharge") : BigDecimal.ZERO; + BigDecimal incrementalTax = incrementalSurcharge.divide(new BigDecimal(10), 2, RoundingMode.HALF_UP); + BigDecimal royalpayTax = taxAmount.subtract(incrementalTax); + BigDecimal realRoyalpayCharge = royalpaySurhcarge + .add(surhcargeBack) + .add(channelSurcharge) + .add(royalpayTax); + item.put("incremental_surcharge", incrementalSurcharge.add(incrementalTax).setScale(2, RoundingMode.HALF_UP)); + item.put("real_royalpay_surcharge", realRoyalpayCharge.setScale(2, RoundingMode.HALF_UP)); + scaleDecimalVal(item, "display_amount", item.getString("currency")); + String platformCurrency = PlatformEnvironment.getEnv().getForeignCurrency(); + scaleDecimalVal(item, "clearing_amount", platformCurrency); + scaleDecimalVal(item, "settle_amount", platformCurrency); + scaleDecimalVal(item, "total_surcharge", platformCurrency); + String debit = item.getString("transaction_type").equals("Debit") ? item.getBigDecimal("clearing_amount").toString() + : "-"; + String credit = item.getString("transaction_type").equals("Credit") ? item.getBigDecimal("clearing_amount").toString() + : "-"; + item.put("debit", debit); + item.put("credit", credit); + item.putIfAbsent("settle_amount", "-"); + }); + view.addObject("parmerters", parmerters); + view.addObject("dataList", dataList); + JSONObject orgInfo = orgManager.getOrgDetail(client.getIntValue("org_id"), null); + if (!orgInfo.containsKey("logo") || orgInfo.getIntValue("org_id") == 1) { + orgInfo.put("logo", "none"); + } + view.addObject("orgInfo", orgInfo); + } catch (Exception e) { + e.printStackTrace(); + } + } + return view; + } + + @Override + public void exportUpayTransFlow(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws + Exception { + JSONObject transFlow = listPartnerTransFlowByExportPdf(query, partner, new String[]{"rpaypmt_card", "rpaypmt_dd"}); JSONObject analysis = transFlow.getJSONObject("analysis"); JSONObject client = clientManager.getClientInfo(partner.getIntValue("client_id")); if (!transFlow.getJSONArray("data").isEmpty()) { @@ -793,7 +970,7 @@ public class TradeLogServiceImpl implements TradeLogService { parmerters.put("royalpay_fee", takeDecimalOrDefault(analysis, "total_royalpay_fee", BigDecimal.ZERO)); parmerters.put("incremental_fee", takeDecimalOrDefault(analysis, "total_incremental_surcharge", BigDecimal.ZERO)); parmerters.put("incremental_gst", takeDecimalOrDefault(analysis, "total_incremental_tax", BigDecimal.ZERO)); - parmerters.put("royalpay_gst", analysis.getBigDecimal("tax_amount").subtract(analysis.getBigDecimal("total_incremental_tax")).setScale(2,RoundingMode.HALF_UP)); + parmerters.put("royalpay_gst", analysis.getBigDecimal("tax_amount").subtract(analysis.getBigDecimal("total_incremental_tax")).setScale(2, RoundingMode.HALF_UP)); BigDecimal totalTransactionFee = analysis.getBigDecimal("total_transaction_fee").add(analysis.getBigDecimal("total_transaction_fee_tax")).setScale(2, RoundingMode.HALF_UP); BigDecimal totalRoyalpayFee = analysis.getBigDecimal("total_surcharge") .subtract(analysis.getBigDecimal("total_transaction_fee")) @@ -817,7 +994,7 @@ public class TradeLogServiceImpl implements TradeLogService { BigDecimal realRoyalpayCharge = item.getBigDecimal("total_surcharge").add(taxAmount).subtract(transactionFee).subtract(transactionFeeTax).subtract(incrementalSurcharge).subtract(incrementalTax); item.put("incremental_surcharge", incrementalSurcharge.add(incrementalTax).setScale(2, RoundingMode.HALF_UP)); item.put("total_surcharge_intax", realRoyalpayCharge.setScale(2, RoundingMode.HALF_UP)); - item.put("transaction_fee_intax", transactionFee.add(transactionFeeTax).setScale(2,RoundingMode.HALF_UP)); + item.put("transaction_fee_intax", transactionFee.add(transactionFeeTax).setScale(2, RoundingMode.HALF_UP)); scaleDecimalVal(item, "display_amount", item.getString("currency")); String platformCurrency = PlatformEnvironment.getEnv().getForeignCurrency(); scaleDecimalVal(item, "clearing_amount", platformCurrency); @@ -843,7 +1020,8 @@ public class TradeLogServiceImpl implements TradeLogService { } @Override - public void exportTransFlowApi(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws Exception { + public void exportTransFlowApi(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws + Exception { query.setClearing_status(-1); String clientKey = "exportTransFlow:" + partner.getString("client_id"); @@ -851,30 +1029,29 @@ public class TradeLogServiceImpl implements TradeLogService { if (client == null) { throw new InvalidShortIdException(); } - partner.put("client_id",client.getIntValue("client_id")); - partner.put("client",client); + partner.put("client_id", client.getIntValue("client_id")); + partner.put("client", client); long internal = 0; - try{ + try { SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd"); long start = formatter.parse(query.getDatefrom()).getTime(); - long end= formatter.parse(query.getDateto()).getTime(); - internal = (end-start)/(1000*60*60*24); - }catch (Exception e){ + long end = formatter.parse(query.getDateto()).getTime(); + internal = (end - start) / (1000 * 60 * 60 * 24); + } catch (Exception e) { throw new ServerErrorException("查询参数格式不正确"); } - if(internal > 90){ - throw new ServerErrorException("最大查询区间为90天,请确认查询区间"); - } + if (internal > 90) { + throw new ServerErrorException("最大查询区间为90天,请确认查询区间"); + } - try{ + try { if (!locker.lock(clientKey, 300_000)) { throw new ServerErrorException("其他Invoice正在生成中,请稍后再试"); } - exportTransFlow( query, partner, response); - } - finally { + exportTransFlow(query, partner, response); + } finally { locker.unlock(clientKey); } } @@ -894,7 +1071,8 @@ public class TradeLogServiceImpl implements TradeLogService { } @Override - public void exportExcel(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws Exception { + public void exportExcel(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws + Exception { logger.debug("excel The method======= exportExcel() start......................."); JSONObject transFlow = listPartnerTransFlow(query, partner); JSONObject client = clientManager.getClientInfo(partner.getIntValue("client_id")); @@ -973,13 +1151,14 @@ public class TradeLogServiceImpl implements TradeLogService { row.createCell(17, Cell.CELL_TYPE_STRING).setCellValue(data.getString("trans_type")); row.createCell(18, Cell.CELL_TYPE_STRING).setCellValue(data.getString("clear_status")); row.createCell(19, Cell.CELL_TYPE_STRING).setCellValue(data.getString("gateway")); - row.createCell(20, Cell.CELL_TYPE_STRING).setCellValue(data.containsKey("order_detail")&&!"".equals(data.getString("order_detail"))?data.getString("order_detail"):data.getString("remark")); + row.createCell(20, Cell.CELL_TYPE_STRING).setCellValue(data.containsKey("order_detail") && !"".equals(data.getString("order_detail")) ? data.getString("order_detail") : data.getString("remark")); row.createCell(21, Cell.CELL_TYPE_STRING).setCellValue(data.getString("dev_id")); } @Override - public void exportExcelNew(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws Exception { + public void exportExcelNew(TradeLogQuery query, JSONObject partner, HttpServletResponse response) throws + Exception { logger.debug("excel The method======= exportExcelNew() start......................."); JSONObject transFlow = listPartnerTransFlow(query, partner); JSONObject client = clientManager.getClientInfo(partner.getIntValue("client_id")); @@ -1078,7 +1257,7 @@ public class TradeLogServiceImpl implements TradeLogService { String credit = dataItem.getString("transaction_type").equals("Credit") ? dataItem.getBigDecimal("clearing_amount").toString() : "-"; HSSFRichTextString text3 = new HSSFRichTextString(credit); - HSSFRichTextString text4 = new HSSFRichTextString(dataItem.containsKey("order_detail")?dataItem.getString("order_detail"):dataItem.getString("remark")); + HSSFRichTextString text4 = new HSSFRichTextString(dataItem.containsKey("order_detail") ? dataItem.getString("order_detail") : dataItem.getString("remark")); cell0.setCellValue(text0); cell1.setCellValue(text1); cell2.setCellValue(text2); @@ -1800,7 +1979,8 @@ public class TradeLogServiceImpl implements TradeLogService { } @Override - public void exportExcelAllPartner(TradeLogQuery query, JSONObject partner, HttpServletResponse resp) throws Exception { + public void exportExcelAllPartner(TradeLogQuery query, JSONObject partner, HttpServletResponse resp) throws + Exception { logger.debug("excel The method======= exportExcel() start......................."); int clientId1 = partner.getIntValue("client_id"); String timezone = partner.getJSONObject("client").getString("timezone"); @@ -1825,7 +2005,7 @@ public class TradeLogServiceImpl implements TradeLogService { String[] clientIds = query.getClient_ids(); List clientIdList = new ArrayList<>(); clientIdList.add("ALL"); - if (clientIds!=null && clientIds.length >= 2) { + if (clientIds != null && clientIds.length >= 2) { clientIdList.addAll(Arrays.asList(clientIds)); } HSSFSheet sheet = null; diff --git a/src/main/java/au/com/royalpay/payment/manage/tradelog/web/ManageTradelogController.java b/src/main/java/au/com/royalpay/payment/manage/tradelog/web/ManageTradelogController.java index f81569efb..a54a2360d 100644 --- a/src/main/java/au/com/royalpay/payment/manage/tradelog/web/ManageTradelogController.java +++ b/src/main/java/au/com/royalpay/payment/manage/tradelog/web/ManageTradelogController.java @@ -27,6 +27,7 @@ public class ManageTradelogController { private TradeLogService tradeLogService; @Resource private ClientManager clientManager; + @RequestMapping(method = RequestMethod.GET) @ReadOnlyConnection @RequireManager(role = {ManagerRole.ADMIN, ManagerRole.BD_USER, ManagerRole.OPERATOR, ManagerRole.FINANCIAL_STAFF, ManagerRole.SERVANT, ManagerRole.DIRECTOR}) @@ -34,7 +35,7 @@ public class ManageTradelogController { return tradeLogService.listAllTradeLogs(query, manager); } - @RequestMapping(value = "/incremental",method = RequestMethod.GET) + @RequestMapping(value = "/incremental", method = RequestMethod.GET) @ReadOnlyConnection @RequireManager(role = {ManagerRole.ADMIN, ManagerRole.BD_USER, ManagerRole.OPERATOR, ManagerRole.FINANCIAL_STAFF, ManagerRole.SERVANT, ManagerRole.DIRECTOR}) public JSONObject listAllIncrementalTradeLogs(TradeLogQuery query, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) { @@ -52,30 +53,30 @@ public class ManageTradelogController { @ManagerMapping(value = "/report/excel", method = RequestMethod.GET) @ReadOnlyConnection public void exportExcel(TradeLogQuery query, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager, HttpServletResponse httpResponse) throws Exception { - tradeLogService.exportTransLog(query,manager,httpResponse); + tradeLogService.exportTransLog(query, manager, httpResponse); } - @ManagerMapping(value = "/trans_flow",method = RequestMethod.GET,role = {ManagerRole.FINANCIAL_STAFF}) + @ManagerMapping(value = "/trans_flow", method = RequestMethod.GET, role = {ManagerRole.FINANCIAL_STAFF}) @ReadOnlyConnection - public JSONObject listTransFlow(TradeLogQuery query,@RequestParam(required = true) String client_moniker) throws Exception { - return tradeLogService.listPartnerTransFlowPage(query,getPartnerParams(client_moniker)); + public JSONObject listTransFlow(TradeLogQuery query, @RequestParam String client_moniker) throws Exception { + return tradeLogService.listPartnerTransFlowPage(query, getPartnerParams(client_moniker)); } - @ManagerMapping(value = "/trans_flow/pdf", method = RequestMethod.GET,role = {ManagerRole.FINANCIAL_STAFF}) + @ManagerMapping(value = "/trans_flow/pdf", method = RequestMethod.GET, role = {ManagerRole.FINANCIAL_STAFF}) @ReadOnlyConnection - public void exportTransFlowPDF(TradeLogQuery query, @RequestParam(required = true) String client_moniker, HttpServletResponse httpResponse) throws Exception { - tradeLogService.exportTransFlow(query,getPartnerParams(client_moniker),httpResponse); + public void exportTransFlowPDF(TradeLogQuery query, @RequestParam String client_moniker, HttpServletResponse httpResponse) throws Exception { + tradeLogService.exportTransFlow(query, getPartnerParams(client_moniker), httpResponse); } - private JSONObject getPartnerParams(String clientMoniker){ + private JSONObject getPartnerParams(String clientMoniker) { JSONObject client = clientManager.getClientInfoByMoniker(clientMoniker); - if(client==null){ + if (client == null) { throw new NotFoundException("Client Not Exists"); } JSONObject params = new JSONObject(); - params.put("client_id",client.getIntValue("client_id")); - params.put("client",client); - params.put("client_moniker",clientMoniker); + params.put("client_id", client.getIntValue("client_id")); + params.put("client", client); + params.put("client_moniker", clientMoniker); return params; } } diff --git a/src/main/resources/templates/app/invoice.html b/src/main/resources/templates/app/invoice.html new file mode 100644 index 000000000..73555826b --- /dev/null +++ b/src/main/resources/templates/app/invoice.html @@ -0,0 +1,221 @@ + + + + + + + + + + [[${#dates.format((new java.util.Date()), 'dd-MM-yyyy')}]] [[${parmerters.partnerCode}]] Invoice + + + + + + + + + + + Tunnel Show Pty Ltd trading as RoyalPay + ABN 16 601 619 685 + Representative of AFSL 448066 + + + + + + + Tax Invoice + + Merchant code + + Statement + + + Issue Date + + + Current + + + + + Your Statement + + + + Date/Time + + + Transaction ID + + + + Debit + + + + Credit + + + + Service Fee for RoyalPay (GST inclu) + + + + Service fee for Mini Program(GST Inclu) + + + + Settlement Amount + + + + + + + + + + + + + - + + + + - + + + + + + + + + + + + + + + + + diff --git a/src/main/ui/static/templates/mch_invoice.css b/src/main/ui/static/templates/mch_invoice.css new file mode 100644 index 000000000..32a5b27a1 --- /dev/null +++ b/src/main/ui/static/templates/mch_invoice.css @@ -0,0 +1,108 @@ +.divcontent { + width: 100%; + height: auto; + float: left; + margin: 1px; + align-items: start; + display: flex; + text-align: center; + margin-top: 5%; + margin-left: 5%; + margin-right: 5%; +} + +.divcontent_left { + width: 50%; + height: auto; + text-align: left; + float: left; + white-space: normal; + word-break: break-all; + word-wrap: break-word; +} + +.divcontent_right { + width: 50%; + height: auto; + float: right; + text-align: left; + white-space: normal; + word-break: break-all; + word-wrap: break-word; +} + +.divinvoicesTitle { + width: 100%; + height: auto; + float: left; + background: #FF6600; + display: flex; + align-items: center; + text-align: left; + padding-top: 10px; + padding-bottom: 10px; + color: white; +} + +.divinvoicesContent { + width: 100%; + height: auto; + float: left; + background: white;; + display: flex; + flex-wrap: wrap; + align-items: center; + text-align: left; + padding-top: 10px; + padding-bottom: 10px; + color: black; +} + +.divinvoiceItem { + height: auto; + float: left; + padding-left: 3px; + white-space: normal; + word-break: break-all; + word-wrap: break-word; +} + +.spantitle { + color: #FF6600; + font-size: 20px; + height: auto; + font-weight: bold; +} + +.divSumary { + child-align: middle; + border-bottom: 2px solid #000; + margin-bottom: 10px; + padding-bottom: 10px; + width: 85%; +} + +.spancontent-title { + width: 40%; + float: left; + color: #000000; + font-size: 17px; + font-weight: bold; + vertical-align: center; + +} + +.spancontent-value { + color: #000000; + font-size: 17px; + font-weight: bold; + padding-left: 5px; + vertical-align: center; + +} +.statement_title{ + padding-bottom: 2%; + padding-top: 2%; + float: left; + padding-left: 5%; +} diff --git a/src/main/ui/static/templates/payment/v1/card_pay.js b/src/main/ui/static/templates/payment/v1/card_pay.js index 8506924ab..8ebbabd84 100644 --- a/src/main/ui/static/templates/payment/v1/card_pay.js +++ b/src/main/ui/static/templates/payment/v1/card_pay.js @@ -10,7 +10,16 @@ $(function () { data: JSON.stringify(secretData), contentType: 'application/json', method: 'POST', - success: function () { + success: function (res) { + if (res.sdk_params) { + let threeDsParams = JSON.parse(res.sdk_params); + let form = $('').attr('action', threeDsParams.acs_url).attr('method', 'post').css('display', 'none'); + $('').attr('name', 'paReq').val(threeDsParams.pa_req).attr('type', 'hidden').appendTo(form); + $('').attr('name', 'TermURL').val(threeDsParams.term_url).attr('type', 'hidden').appendTo(form); + $(body).append(form); + form.commit(); + return; + } startCheckOrder(window.client_moniker, window.partner_order_id); }, error: function (jqXHR) {