Merge branch 'develop_risk' into develop

# Conflicts:
#	src/main/java/au/com/royalpay/payment/manage/customers/core/impls/CouponValidateServiceImpl.java
#	src/main/java/au/com/royalpay/payment/manage/mappers/payment/OrderMapper.java
#	src/main/java/au/com/royalpay/payment/manage/merchants/core/ClientManager.java
#	src/main/java/au/com/royalpay/payment/manage/merchants/core/impls/ClientManagerImpl.java
#	src/main/resources/au/com/royalpay/payment/manage/mappers/payment/OrderMapper.xml
master
james.zhao 6 years ago
commit c1b5e90235

@ -4,8 +4,12 @@ import cn.yixblog.support.mybatis.autosql.annotations.AutoMapper;
import cn.yixblog.support.mybatis.autosql.annotations.AutoSql;
import cn.yixblog.support.mybatis.autosql.annotations.SqlType;
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 java.util.List;
/**
* @Author lvjian
* @Date 2018/10/10 10:25
@ -19,6 +23,11 @@ public interface RiskEventMapper {
@AutoSql(type = SqlType.UPDATE)
void update(JSONObject riskEvent);
@AutoSql(type = SqlType.SELECT)
List<JSONObject> findAll(JSONObject params);
PageList<JSONObject> listRisksByPage(JSONObject params, PageBounds pageBounds);
@AutoSql(type = SqlType.SELECT)
JSONObject findById(@Param("risk_id") String riskId);

@ -0,0 +1,18 @@
package au.com.royalpay.payment.manage.mappers.riskbusiness;
import cn.yixblog.support.mybatis.autosql.annotations.AutoMapper;
import cn.yixblog.support.mybatis.autosql.annotations.AutoSql;
import cn.yixblog.support.mybatis.autosql.annotations.SqlType;
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@AutoMapper(tablename = "risk_file", pkName = "file_id")
public interface RiskFileMapper {
@AutoSql(type= SqlType.INSERT)
void save(JSONObject file);
@AutoSql(type= SqlType.SELECT)
List<JSONObject> findAllFiles(@Param("material_id") String material_id);
}

@ -0,0 +1,20 @@
package au.com.royalpay.payment.manage.mappers.riskbusiness;
import cn.yixblog.support.mybatis.autosql.annotations.AutoMapper;
import cn.yixblog.support.mybatis.autosql.annotations.AutoSql;
import cn.yixblog.support.mybatis.autosql.annotations.SqlType;
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@AutoMapper(tablename = "risk_material", pkName = "material_id")
public interface RiskMaterialMapper {
@AutoSql(type = SqlType.INSERT)
void save(JSONObject material);
List<JSONObject> findAllMaterials(@Param("risk_id") String risk_id);
}

@ -25,6 +25,8 @@ public interface ClientBDMapper {
List<JSONObject> listClientBDInfoAvailable(@Param("client_id") int clientId, @Param("date") Date date);
List<JSONObject> listBDClientInfo(JSONObject param);
void updateClientDB(JSONObject jsonObject);
@AutoSql(type = SqlType.UPDATE)

@ -36,6 +36,10 @@ public interface ClientMapper {
@AutoSql(type = SqlType.SELECT)
JSONObject findClientByMonikerAll(@Param("client_moniker") String clientMoniker);
@AutoSql(type = SqlType.SELECT)
@AdvanceSelect(addonWhereClause = "is_valid=1")
List<JSONObject> getClientBySubMerchantId(@Param("sub_merchant_id") String subMerchantId);
PageList<JSONObject> listPartners(JSONObject params, PageBounds pagination);
PageList<JSONObject> comListPartners(JSONObject params, PageBounds pagination);

@ -351,4 +351,6 @@ public interface ClientManager {
boolean postponeClientRate(int clientId, String clientMoniker,String nextYearExipryDate);
JSONObject comListPartnerSelection(JSONObject manager, PartnerQuery query);
List<JSONObject> getClientBySimpleQuery(JSONObject param);
}

@ -4029,6 +4029,14 @@ public class ClientManagerImpl implements ClientManager, ManagerTodoNoticeProvid
});
}
@Override
public List<JSONObject> getClientBySimpleQuery(JSONObject param) {
String subMerchantId = param.getString("sub_merchant_id");
if (StringUtils.isNotBlank(subMerchantId)) {
return clientMapper.getClientBySubMerchantId(subMerchantId);
}
return null;
}
@Override
@Transactional
public boolean postponeClientRate(int clientId, String clientMoniker, String nextYearExipryDate) {

@ -17,6 +17,8 @@ public interface MailService {
String sendEmail(String title, String mailTos, String mailCcs, String content, List<JSONObject> attachFiles) throws URISyntaxException, IOException;
String sendRiskEmail(String title, String mailTos, String mailCcs, String content, List<JSONObject> attachFiles, int order_type) throws URISyntaxException, IOException;
List<JSONObject> checkEmailStatus(String emailId);
void removeUnsub(Long id);

@ -266,4 +266,39 @@ public class MailServiceImp implements MailService {
}
}
@Override
public String sendRiskEmail(String title, String mailTos, String mailCcs, String content, List<JSONObject> attachFiles, int order_type) throws URISyntaxException, IOException {
NoticeBean noticeBean = new NoticeBean();
noticeBean.setTitle(title);
List<JSONObject> mailClients = new ArrayList<>();
JSONObject mailClient = new JSONObject();
mailClient.put("mailto", mailTos);
mailClient.put("mailcc", mailCcs);
mailClients.add(mailClient);
noticeBean.setMailClients(mailClients);
noticeBean.setContent(content);
noticeBean.setAttachFiles(attachFiles);
noticeBean.setSenderAddress("riskcontrol@royalpay.com.au");
noticeBean.setPassword("RPrisk123");
if(order_type == 1 || order_type == 2){
noticeBean.setSenderAddress("risk@royalpay.com.au");
noticeBean.setPassword("Tunnelrisk123");
}
String postUrl = mailHost + "/mail/single?" + generateMailSignParam();
HttpRequestResult result = null;
try {
logger.info("===sendEmail===noticeBean:" + JSON.toJSON(noticeBean));
result = new HttpRequestGenerator(postUrl, RequestMethod.POST).setJSONEntity(noticeBean).setTimeout(60_000).execute();
if (result.isSuccess()) {
String mail_id = result.getResponseContentJSONObj().getString("mail_id");
return mail_id;
//System.out.println("send Mail=============="+mail_id);
} else {
throw new ServerErrorException("Error Connection");
}
} catch (URISyntaxException e) {
throw new ServerErrorException("Error Connection");
}
}
}

@ -0,0 +1,201 @@
package au.com.royalpay.payment.manage.riskbusiness.bean;
import au.com.royalpay.payment.core.exceptions.ParamInvalidException;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
/**
* @Author lvjian
* @Date 2018/10/10 11:27
*/
public class RiskEventQuery {
// 调单类型
private Integer orderType;
// 商户编码
private String clientMoniker;
// 子商户号
private String subMerchantId;
// 订单号(多个,以逗号分隔)
private String orderIds;
// 邮件发送状态
private Integer emailStatus;
// 行业
private String industry;
// 处理结果
private Integer resultType;
// 收到调单邮件日期
private String receiveEmailDate;
// 邮件回复截止日期
private String replyEmailDate;
private Integer page = 1;
// 金额区间
private String startAmount;
private String endAmount;
public String getStartAmount() {
return startAmount;
}
public void setStartAmount(String startAmount) {
this.startAmount = startAmount;
}
public String getEndAmount() {
return endAmount;
}
public void setEndAmount(String endAmount) {
this.endAmount = endAmount;
}
public Integer getOrderType() {
return orderType;
}
public void setOrderType(Integer orderType) {
this.orderType = orderType;
}
public String getClientMoniker() {
return clientMoniker;
}
public void setClientMoniker(String clientMoniker) {
this.clientMoniker = clientMoniker;
}
public String getSubMerchantId() {
return subMerchantId;
}
public void setSubMerchantId(String subMerchantId) {
this.subMerchantId = subMerchantId;
}
public String getOrderIds() {
return orderIds;
}
public void setOrderIds(String orderIds) {
this.orderIds = orderIds;
}
public Integer getEmailStatus() {
return emailStatus;
}
public void setEmailStatus(Integer emailStatus) {
this.emailStatus = emailStatus;
}
public String getIndustry() {
return industry;
}
public void setIndustry(String industry) {
this.industry = industry;
}
public Integer getResultType() {
return resultType;
}
public void setResultType(Integer resultType) {
this.resultType = resultType;
}
public String getReceiveEmailDate() {
return receiveEmailDate;
}
public void setReceiveEmailDate(String receiveEmailDate) {
this.receiveEmailDate = receiveEmailDate;
}
public String getReplyEmailDate() {
return replyEmailDate;
}
public void setReplyEmailDate(String replyEmailDate) {
this.replyEmailDate = replyEmailDate;
}
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public JSONObject toJSON() {
JSONObject params = new JSONObject();
if (orderType != null && orderType >= 1) {
params.put("order_type", orderType);
}
if (StringUtils.isNotBlank(clientMoniker)) {
params.put("client_moniker", clientMoniker);
}
if (StringUtils.isNotBlank(subMerchantId)) {
params.put("sub_merchant_id", subMerchantId);
}
if (StringUtils.isNotBlank(orderIds)) {
orderIds = orderIds.trim().replace("", ",");
params.put("order_ids", orderIds);
}
if (emailStatus != null && emailStatus >= 0) {
params.put("email_status", emailStatus);
}
if (resultType != null && resultType >= 0) {
params.put("result_type", resultType);
}
if (StringUtils.isNotBlank(industry)) {
params.put("industry", industry);
}
if (receiveEmailDate != null) {
params.put("receive_email_date", receiveEmailDate);
}
if (replyEmailDate != null) {
params.put("reply_email_date", replyEmailDate);
}
if (page != null && page > 0) {
params.put("page", page);
}
if (StringUtils.isNotBlank(startAmount)) {
params.put("start_amount", startAmount);
}
if (StringUtils.isNotBlank(endAmount)) {
params.put("end_amount", endAmount);
}
return params;
}
}

@ -1,10 +1,87 @@
package au.com.royalpay.payment.manage.riskbusiness.core;
import com.alibaba.fastjson.JSONObject;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* @Author lvjian
* @Date 2018/10/10 10:29
*/
public interface RiskBusinessService {
/**
*
* @param params
* @return
*/
List<JSONObject> getRiskEvents(JSONObject params);
/**
*
* @param params
* @return
*/
JSONObject getRiskEventsByPage(JSONObject params, JSONObject manager);
/**
*
* @param riskId
* @return
*/
JSONObject getRiskEventDetail(String riskId);
/**
*
* @param orderIds
* @return
*/
List<JSONObject> getRiskEventOrderList(String orderIds);
/**
*
* @param params
*/
void addRiskEvent(JSONObject params, JSONObject manager);
/**
*
* @param params
*/
void updateRiskEvent(JSONObject params);
/**
* zip
* @param riskId
*/
void downloadAuditMaterialZiP(String riskId, HttpServletResponse response);
/**
*
* @param riskId
*/
void sendUploadEmail(String riskId) throws IOException;
/**
*
* @param riskId
*/
void sendRefuseEmail(String riskId) throws IOException;
/**
*
* @param riskId
*/
void sendUrgeEmail(String riskId) throws IOException;
/**
*
* @param param
* @return
*/
JSONObject getRiskMaterial(JSONObject param);
}

@ -0,0 +1,24 @@
package au.com.royalpay.payment.manage.riskbusiness.core;
import com.alibaba.fastjson.JSONObject;
public interface RiskUploadService {
/**
*
* @param material
*/
void submitMaterial(JSONObject material);
/**
*
* @param codeKey
*/
void deleteUploadMailKey(String codeKey);
/**
*
* @param codeKey
* @param risk_id
*/
void checkUploadMailKey(String codeKey,String risk_id);
}

@ -1,12 +1,624 @@
package au.com.royalpay.payment.manage.riskbusiness.core.impl;
import au.com.royalpay.payment.core.exceptions.EmailException;
import au.com.royalpay.payment.core.exceptions.InvalidShortIdException;
import au.com.royalpay.payment.core.exceptions.OrderNotExistsException;
import au.com.royalpay.payment.core.exceptions.OrderNotMatchException;
import au.com.royalpay.payment.manage.mappers.log.AppMessageLogMapper;
import au.com.royalpay.payment.manage.mappers.payment.OrderMapper;
import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskEventMapper;
import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskFileMapper;
import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskMaterialMapper;
import au.com.royalpay.payment.manage.mappers.system.ClientDeviceTokenMapper;
import au.com.royalpay.payment.manage.mappers.system.ClientMapper;
import au.com.royalpay.payment.manage.mappers.system.ClientBDMapper;
import au.com.royalpay.payment.manage.merchants.beans.PartnerQuery;
import au.com.royalpay.payment.manage.notice.core.MailService;
import au.com.royalpay.payment.manage.pushMessage.bean.AppManagerMessageBuilder;
import au.com.royalpay.payment.manage.riskbusiness.core.RiskBusinessService;
import au.com.royalpay.payment.manage.riskbusiness.enums.RiskResultTypeEnum;
import au.com.royalpay.payment.manage.signin.beans.TodoNotice;
import au.com.royalpay.payment.manage.signin.core.ManagerTodoNoticeProvider;
import au.com.royalpay.payment.manage.tradelog.core.TradeLogService;
import au.com.royalpay.payment.manage.riskbusiness.enums.RiskOrderTypeEnum;
import au.com.royalpay.payment.tools.device.message.AppMessage;
import au.com.royalpay.payment.tools.device.message.AppMsgSender;
import au.com.royalpay.payment.tools.env.PlatformEnvironment;
import au.com.royalpay.payment.tools.exceptions.BadRequestException;
import au.com.royalpay.payment.tools.locale.LocaleSupport;
import au.com.royalpay.payment.tools.permission.enums.ManagerRole;
import au.com.royalpay.payment.tools.exceptions.ServerErrorException;
import au.com.royalpay.payment.tools.threadpool.RoyalThreadPoolExecutor;
import au.com.royalpay.payment.tools.utils.PageListUtils;
import com.alibaba.fastjson.JSONObject;
import com.github.miemiedev.mybatis.paginator.domain.Order;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring4.SpringTemplateEngine;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.util.*;
import javax.annotation.Resource;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import java.util.concurrent.TimeUnit;
/**
* @Author lvjian
* @Date 2018/10/10 10:30
*/
@Service
public class RiskBusinessServiceImpl implements RiskBusinessService {
public class RiskBusinessServiceImpl implements RiskBusinessService, ManagerTodoNoticeProvider {
private Logger logger = LoggerFactory.getLogger(RiskBusinessServiceImpl.class);
@Resource
private RiskEventMapper riskEventMapper;
@Resource
private ClientMapper clientMapper;
@Resource
private ClientBDMapper clientBDMapper;
@Resource
private OrderMapper orderMapper;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private SpringTemplateEngine thymeleaf;
@Resource
private MailService mailService;
@Resource
private TradeLogService tradeLogService;
@Resource
private RoyalThreadPoolExecutor royalThreadPoolExecutor;
private final String UPLOAD_MAIL_PREFIX = "UPLOAD_MAIL";
@Autowired
private RiskMaterialMapper riskMaterialMapper;
@Resource
private RiskFileMapper riskFileMapper;
@Resource
private ClientDeviceTokenMapper clientDeviceTokenMapper;
@Resource
private AppMessageLogMapper appMessageLogMapper;
private Map<String, AppMsgSender> senderMap = new HashMap<>();
private ThreadPoolExecutor sendingAppleMsgPool = new ThreadPoolExecutor(10, 30, 5, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
@Override
public List<JSONObject> getRiskEvents(JSONObject params) {
return riskEventMapper.findAll(params);
}
@Override
public JSONObject getRiskEventsByPage(JSONObject params, JSONObject manager) {
// 如果登录的角色是BD添加查询条件result_type为1,2,3,4order_type为1或者2
if (ManagerRole.BD_USER.hasRole(manager.getIntValue("role"))) {
params.put("bd_id", manager.getString("manager_id"));
List<Integer> orderTypes = Arrays.asList(RiskOrderTypeEnum.WECHAT_ORDER.getOrderType(),
RiskOrderTypeEnum.ALIPAY_ORDER.getOrderType());
params.put("order_types", orderTypes);
List<Integer> resultTypes = Arrays.asList(RiskResultTypeEnum.SEND_EMAIL_TO_BD.getResultType(),
RiskResultTypeEnum.WAIT_FOR_AUDIT.getResultType(),
RiskResultTypeEnum.MATERIAL_AUDIT_PASS.getResultType(),
RiskResultTypeEnum.MATERIAL_NOT_PASS.getResultType());
params.put("result_types", resultTypes);
}
PageList<JSONObject> riskEvents = riskEventMapper.listRisksByPage(params, new PageBounds(params.getInteger("page"), 10, Order.formString("create_time.desc")));
return PageListUtils.buildPageListResult(riskEvents);
}
@Override
public JSONObject getRiskEventDetail(String riskId) {
JSONObject riskEventDetail = riskEventMapper.findById(riskId);
// 获取商户信息
JSONObject client = null;
String clientMoniker = riskEventDetail.getString("client_moniker");
if (clientMoniker != null) {
client = clientMapper.findClientByMonikerAll(clientMoniker);
if (client == null) {
throw new InvalidShortIdException();
}
}
riskEventDetail.put("clientInfo", client);
return riskEventDetail;
}
@Override
public List<JSONObject> getRiskEventOrderList(String orderIds) {
List<JSONObject> tradeLogs = new ArrayList<>();
if (StringUtils.isNotBlank(orderIds)) {
String[] orderIdArray = orderIds.trim().split(",");
JSONObject query = new JSONObject();
// 获取订单信息
for (int i = 0; i < orderIdArray.length; i++) {
JSONObject orderInfo = orderMapper.findOrderById(orderIdArray[i]);
tradeLogs.add(orderInfo);
}
}
return tradeLogs;
}
@Override
public void addRiskEvent(JSONObject params, JSONObject manager) {
// 通用号调单不需要填写client_moniker
JSONObject client = null;
String clientMoniker = params.getString("client_moniker");
if (clientMoniker != null) {
client = clientMapper.findClientByMoniker(clientMoniker);
if(client == null){
throw new InvalidShortIdException();
}
}
params.put("fillin_id", manager.getString("manager_id"));
params.put("fillin_person", manager.getString("display_name"));
String orderIds = params.getString("order_ids");
if (StringUtils.isNotBlank(orderIds)) {
orderIds = orderIds.trim().replace("", ",");
params.put("order_ids", orderIds);
String[] orderIdArray = orderIds.split(",");
List<String> orderAmountList = new ArrayList<>();
for (int i = 0; i < orderIdArray.length; i++) {
JSONObject orderInfo = orderMapper.findOrderById(orderIdArray[i]);
// 判断该笔订单是否存在,是否属于该商户
if (orderInfo == null)
throw new OrderNotExistsException();
else {
if (!clientMoniker.equals(orderInfo.getString("partner_code"))) {
throw new OrderNotMatchException();
}
orderAmountList.add(orderInfo.getString("total_amount"));
}
}
params.put("order_amounts", StringUtils.join(orderAmountList, ","));
}
riskEventMapper.save(params);
}
@Override
public void updateRiskEvent(JSONObject params) {
riskEventMapper.update(params);
}
@Override
public void downloadAuditMaterialZiP(String riskId, HttpServletResponse response) {
JSONObject riskEvent = riskEventMapper.findById(riskId);
String clientMoniker = riskEvent.getString("client_moniker");
JSONObject param = new JSONObject();
param.put("risk_id", riskId);
param.put("orderby_type", "update_time");
JSONObject riskMaterial = getRiskMaterial(param);
try {
String downloadFilename = clientMoniker + "_audit_materials_" + DateFormatUtils.format(new Date(), "dd/MM/yyyy HH:mm:ss").toString() + ".zip";
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" + downloadFilename);
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
for(int i=1;i<=6;i++){
if(riskMaterial.containsKey("file"+i)){
List<String> fileList= (List<String>)riskMaterial.get("file"+i);
for(String fileUrl : fileList){
zos.putNextEntry(new ZipEntry("file" + i+fileUrl.substring(fileUrl.lastIndexOf("/"))));
InputStream inputStream = new URL(fileUrl).openConnection().getInputStream();
byte[] buffer = new byte[1024];
int result = 0;
while ((result = inputStream.read(buffer)) != -1) {
zos.write(buffer, 0, result);
}
inputStream.close();
}
}
}
zos.flush();
zos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void sendUploadEmail(String riskId) throws IOException {
JSONObject event = getRiskEventDetail(riskId);
Context ctx = getMailContext(event);
final List<String> emailsTos = (List<String>)ctx.getVariable("emailsTos");
final List<String> emailsCcs = ctx.getVariable("emailsCcs")==null?new ArrayList<>():(List<String>)ctx.getVariable("emailsCcs");
final String title = (String)ctx.getVariable("title");
final String content = thymeleaf.process("mail/risk_upload_mail.html", ctx);
final String uploadUrl = (String)ctx.getVariable("uploadUrl");
royalThreadPoolExecutor.execute(() -> {
try {
String emailId = mailService.sendRiskEmail(title, emailsTos.isEmpty() ? "" : StringUtils.join(emailsTos, ","),
emailsCcs.isEmpty() ? "" : StringUtils.join(emailsCcs, ","), content, event.getIntValue("order_type")==3?(List<JSONObject>)ctx.getVariable("files"):null,event.getIntValue("order_type"));
event.put("email_status",1);
event.put("result_type", RiskResultTypeEnum.SEND_EMAIL_TO_BD.getResultType());
event.put("submit_url",uploadUrl);
Integer orderType = event.getInteger("order_type");
if (orderType == RiskOrderTypeEnum.WARNING_ORDER.getOrderType()) {
event.put("result_type", RiskResultTypeEnum.ALREADY_HANDLED.getResultType());
}
riskEventMapper.update(event);
} catch (Exception e) {
throw new EmailException("Email Sending Failed", e);
}
});
if(event.getIntValue("order_type")==3){
sendAppRiskMessage(event);
}
}
private void sendAppRiskMessage(JSONObject event){
JSONObject client = clientMapper.findClientByMoniker(event.getString("client_moniker"));
logger.debug("sendRiskAppMessage-" + client.getString("client_moniker") + "-" + "risk_id:"+event.getString("risk_id"));
List<JSONObject> tokens = clientDeviceTokenMapper.listTokensByClient_id(client.getIntValue("client_id"));
for (final JSONObject devToken : tokens) {
Runnable task = () -> {
String token = devToken.getString("token");
if (token == null) {
return;
}
JSONObject log = saveAppMessageLog(devToken.getString("dev_id"), devToken.getIntValue("client_id"), "risk", token,
event.getString("risk_id"));
try {
event.put("send_type", "risk");
JSONObject type = new JSONObject();
type.put("send_type", "risk");
type.put("id", event.getString("risk_id"));
AppMsgSender sender = senderMap.get(devToken.getString("client_type"));
if (token == null || sender == null) {
return;
}
JSONObject managerMsg = new JSONObject();
managerMsg.put("title", LocaleSupport.localeMessage("app.message.title.risk"));
managerMsg.put("body",
LocaleSupport.localeMessage("app.message.body.risk"));
managerMsg.put("type", type);
managerMsg.put("data", event);
managerMsg.put("msgType", "risk");
AppMessage appMessage = new AppManagerMessageBuilder(managerMsg).buildMessage();
sender.sendMessage(appMessage, devToken);
log.put("status", 2);
appMessageLogMapper.update(log);
} catch (Exception e) {
logger.error("出错了:" + e.getMessage());
appMessageLogMapper.updateStatus(log.getString("send_id"), 1, e.getMessage());
throw new ServerErrorException("Send App " + devToken.getString("client_type") + " Failed", e);
}
};
sendingAppleMsgPool.execute(task);
}
}
private JSONObject saveAppMessageLog(String dev_id, int client_id, String messageType, String dev_token, String remark) {
JSONObject log = new JSONObject();
log.put("dev_id", dev_id);
log.put("client_id", client_id);
log.put("msg_type", messageType);
log.put("dev_token", dev_token);
log.put("remark", remark);
log.put("send_time", new Date());
appMessageLogMapper.save(log);
return log;
}
@Override
public void sendRefuseEmail(String riskId) throws IOException {
JSONObject event = getRiskEventDetail(riskId);
Context ctx = getMailContext(event);
ctx.setVariable("refuse",true);
final List<String> emailsTos = (List<String>)ctx.getVariable("emailsTos");
final List<String> emailsCcs = ctx.getVariable("emailsCcs")==null?new ArrayList<>():(List<String>)ctx.getVariable("emailsCcs");
final String uploadUrl = (String)ctx.getVariable("uploadUrl");
final String content = thymeleaf.process("mail/risk_upload_mail.html", ctx);
royalThreadPoolExecutor.execute(() -> {
try {
String emailId = mailService.sendRiskEmail("You need to resubmit risk materials", emailsTos.isEmpty() ? "" : StringUtils.join(emailsTos, ","),
emailsCcs.isEmpty() ? "" : StringUtils.join(emailsCcs, ","), content, event.getIntValue("order_type")==3?(List<JSONObject>)ctx.getVariable("files"):null,event.getIntValue("order_type"));
event.put("email_status",2);
event.put("result_type",RiskResultTypeEnum.MATERIAL_NOT_PASS.getResultType());
event.put("submit_url",uploadUrl);
riskEventMapper.update(event);
} catch (Exception e) {
throw new EmailException("Email Sending Failed", e);
}
});
}
@Override
public void sendUrgeEmail(String riskId) throws IOException {
JSONObject event = getRiskEventDetail(riskId);
Context ctx = getMailContext(event);
final List<String> emailsTos = (List<String>)ctx.getVariable("emailsTos");
final List<String> emailsCcs = ctx.getVariable("emailsCcs")==null?new ArrayList<>():(List<String>)ctx.getVariable("emailsCcs");
final String content = thymeleaf.process("mail/risk_urge_mail.html", ctx);
royalThreadPoolExecutor.execute(() -> {
try {
String emailId = mailService.sendRiskEmail("Please submit risk materials as soon as possible", emailsTos.isEmpty() ? "" : StringUtils.join(emailsTos, ","),
emailsCcs.isEmpty() ? "" : StringUtils.join(emailsCcs, ","), content, event.getIntValue("order_type")==3?(List<JSONObject>)ctx.getVariable("files"):null,event.getIntValue("order_type"));
event.put("email_status",3);
riskEventMapper.update(event);
} catch (Exception e) {
throw new EmailException("Email Sending Failed", e);
}
});
}
private Context getMailContext(JSONObject event) throws IOException {
JSONObject client = clientMapper.findClientByMonikerAll(event.getString("client_moniker"));
if (client == null) {
throw new InvalidShortIdException();
}
String codeKey = RandomStringUtils.random(20, true, true);
while(stringRedisTemplate.boundValueOps(getRiskUploadKey(codeKey)).get()!=null ){
codeKey = RandomStringUtils.random(20, true, true);
}
String codeKeyValue = RandomStringUtils.random(10, true, true);
String expireDay = "7";
if(event.getIntValue("order_type")>2){
expireDay = "3";
}
stringRedisTemplate.boundValueOps(getRiskUploadKey(codeKey)).set(codeKeyValue, Long.parseLong(expireDay), TimeUnit.DAYS);
String uploadUrl = PlatformEnvironment.getEnv().concatUrl("/risk/upload/") + event.getString("risk_id") + "/" + codeKey;
List<JSONObject> bds = clientBDMapper.listClientBDInfoAvailable(client.getIntValue("client_id"), new Date());
List<String> bdNames = new ArrayList<>();
List<String> bdEmails = new ArrayList<>();
for (JSONObject bd : bds) {
String bdName = bd.getString("display_name");
if (StringUtils.isNotEmpty(bdName)) {
bdNames.add(bdName);
}
String email = bd.getString("email");
if (StringUtils.isNotEmpty(email)) {
bdEmails.add(email);
}
}
List<String> clientEmails = new ArrayList<>();
clientEmails.add(client.getString("contact_email"));
String bdNamesStr = bdNames.isEmpty() ? "" : StringUtils.join(bdNames, ",");
String reply_date = DateFormatUtils.format(DateUtils.addDays(event.getDate("reply_email_date"),-1),"yyyy年MM月dd日");
String reply_date_english = DateFormatUtils.format(DateUtils.addDays(event.getDate("reply_email_date"),-1),"dd/MM/yyyy");
Context ctx = new Context();
ctx.setVariable("order_type", event.getIntValue("order_type"));
ctx.setVariable("bdNamesStr", bdNamesStr);
ctx.setVariable("reply_date", reply_date);
ctx.setVariable("reply_date_english", reply_date_english);
ctx.setVariable("client", client);
ctx.setVariable("uploadUrl", uploadUrl);
ctx.setVariable("royalpay_order_type", event.getIntValue("royalpay_order_type"));
ctx.setVariable("warning_order_type", event.getIntValue("warning_order_type"));
switch (event.getIntValue("order_type")){
case 1:
case 2:
String[] orderIds = event.getString("order_ids").split(",");
List<JSONObject> orders = new ArrayList();
for(String orderId : orderIds){
JSONObject order = orderMapper.findOrderById(orderId);
if(order==null){
throw new BadRequestException("Order: "+orderId+" not exists");
}
orders.add(order);
}
ctx.setVariable("orders", orders);
ctx.setVariable("title","Your merchants needs to submit risk materials");
ctx.setVariable("emailsTos", bdEmails);
break;
case 3:
List<JSONObject> attachList = new ArrayList<>();
JSONObject file = new JSONObject();
file.put("name", client.getString("short_name")+ "被查单号相关信息.xlsx");
file.put("content", Base64.encodeBase64String(generateRiskOrders(event)));
attachList.add(file);
ctx.setVariable("files",attachList);
case 4:
ctx.setVariable("title","RoyalPay风控调查 — " + client.getString("short_name"));
ctx.setVariable("emailsCcs", bdEmails);
ctx.setVariable("emailsTos", clientEmails);
break;
}
return ctx;
}
private String getRiskUploadKey(String codeKey){
return UPLOAD_MAIL_PREFIX + codeKey;
}
@Override
public JSONObject getRiskMaterial(JSONObject param) {
List<JSONObject> riskMaterialList = riskMaterialMapper.findAllMaterials(param.getString("risk_id"));
if (riskMaterialList != null && riskMaterialList.size() > 0){
List<JSONObject> files = riskFileMapper.findAllFiles(riskMaterialList.get(0).getString("material_id"));
JSONObject fileNew = new JSONObject();
fileNew.put("description",riskMaterialList.get(0).getString("description"));
for(JSONObject file : files){
int fileType = file.getIntValue("file_type");
if(!fileNew.containsKey("file"+fileType)){
List<String> fileList = new ArrayList<>();
fileList.add(file.getString("file_url"));
fileNew.put("file"+fileType,fileList);
}else{
List<String> fileList = (List<String>)fileNew.get("file"+fileType);
fileList.add(file.getString("file_url"));
fileNew.put("file"+fileType,fileList);
}
}
return fileNew;
}
return null;
}
private byte[] generateRiskOrders(JSONObject event) throws IOException {
String[] orderIds = event.getString("order_ids").split(",");
Workbook wb = new XSSFWorkbook();
for(String orderId : orderIds){
JSONObject orderDetail = tradeLogService.getOrderDetail(new JSONObject(), event.getString("client_moniker"), orderId, null);
Sheet sheet = wb.createSheet(orderId);
sheet.setDefaultColumnWidth((short) 40);
Row row0 = sheet.createRow(0);
Row row1 = sheet.createRow(1);
Row row2 = sheet.createRow(2);
Row row3 = sheet.createRow(3);
Row row4 = sheet.createRow(4);
Row row5 = sheet.createRow(5);
Row row6 = sheet.createRow(6);
Row row7 = sheet.createRow(7);
Row row8 = sheet.createRow(8);
Row row9 = sheet.createRow(9);
Row row10 = sheet.createRow(10);
Row row11 = sheet.createRow(11);
Row row12 = sheet.createRow(12);
Row row13 = sheet.createRow(13);
Row row14 = sheet.createRow(14);
Row row15 = sheet.createRow(15);
row0.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Partner");
row0.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(orderDetail.getJSONObject("client").getString("short_name")+"("+orderDetail.getJSONObject("client").getString("client_moniker")+")");
row1.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Order ID");
row1.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(orderDetail.getString("order_id"));
row2.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Platform Transaction ID");
row2.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(orderDetail.getString("system_transaction_id"));
row3.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Order Description");
row3.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(StringUtils.defaultString(orderDetail.getString("order_description")));
row4.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Customer ID");
row4.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(orderDetail.getString("customer_id"));
row5.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("IP");
row5.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(orderDetail.getString("customer_ip"));
row6.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Total Amount");
row6.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(orderDetail.getString("currency")+" "+orderDetail.getString("total_amount"));
row7.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Input Amount");
row7.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(orderDetail.getString("currency")+" "+orderDetail.getString("display_amount"));
row8.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Pay Amount");
row8.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(orderDetail.getString("currency")+" "+orderDetail.getString("customer_payment_amount"));
row9.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Exchange Rate");
row9.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(orderDetail.getString("exchange_rate"));
row10.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Clearing Amount");
row10.createCell(1,Cell.CELL_TYPE_STRING).setCellValue("AUD "+ orderDetail.getString("clearing_amount"));
row11.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Gateway");
row11.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(getGateWay(orderDetail.getIntValue("gateway")));
row12.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Create Time");
row12.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(orderDetail.getString("create_time"));
row13.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Status");
row13.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(getStatus(orderDetail.getIntValue("status")));
row14.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Pay Time");
row14.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(orderDetail.getString("transaction_time"));
row15.createCell(0,Cell.CELL_TYPE_STRING).setCellValue("Order Detail");
row15.createCell(1,Cell.CELL_TYPE_STRING).setCellValue(StringUtils.defaultString(orderDetail.getString("order_detail")));
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
wb.write(bos);
bos.flush();
return bos.toByteArray();
}
private String getGateWay(int gateWay){
switch (gateWay) {
case 0:
return "线下扫码";
case 1:
return "线下扫码";
case 2:
return "商户静态码";
case 3:
return "线上网关";
case 4:
return "JSAPI网关";
case 5:
return "线下网关";
case 6:
return "线下网关";
case 7:
return "商户静态码";
case 8:
return "Mobile H5";
case 9:
return "第三方网关";
case 10:
return "APP网关";
case 11:
return "账单码";
case 12:
return "小程序";
case 13:
return "原生二维码";
case 14:
return "账单链接";
}
return "";
}
private String getStatus(int status){
switch (status) {
case 0:
return "Creating";
case 1:
return "Failed Create Order";
case 2:
return "Wait For Payment";
case 3:
return "Closed";
case 4:
return "Payment Failed";
case 5:
return "Payment Success";
case 6:
return "Partial Refund";
case 7:
return "Full Refund";
}
return "";
}
@Override
public void checkTodo(JSONObject manager, List<TodoNotice> notices) {
if (ManagerRole.BD_USER.hasRole(manager.getIntValue("role"))) {
JSONObject params = new JSONObject();
params.put("bd_id", manager.getString("manager_id"));
params.put("date", new Date());
List<JSONObject> riskClientList = clientBDMapper.listBDClientInfo(params);
boolean noticeFlag = false;
for (JSONObject client : riskClientList) {
if (!noticeFlag) {
params.put("client_moniker", client.getString("client_moniker"));
List<JSONObject> riskEventList = riskEventMapper.findAll(params);
for (JSONObject event : riskEventList) {
Integer resultType = event.getIntValue("result_type");
Integer orderType = event.getIntValue("order_type");
// Integer是对象所以用equals方法比较
if ((resultType.equals(RiskResultTypeEnum.SEND_EMAIL_TO_BD.getResultType()) || resultType.equals(RiskResultTypeEnum.MATERIAL_NOT_PASS.getResultType())) && (orderType.equals(RiskOrderTypeEnum.WECHAT_ORDER.getOrderType()) || orderType.equals(RiskOrderTypeEnum.ALIPAY_ORDER.getOrderType()))) {
noticeFlag = true;
break;
}
}
} else {
break;
}
}
if (noticeFlag) {
String msg = LocaleSupport.localeMessage("todo.bd.order");
notices.add(new TodoNotice("riskBusiness", msg, "#/analysis/monitoring/risk_business_bd"));
}
}
}
}

@ -0,0 +1,90 @@
package au.com.royalpay.payment.manage.riskbusiness.core.impl;
import au.com.royalpay.payment.core.exceptions.EmailException;
import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskEventMapper;
import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskFileMapper;
import au.com.royalpay.payment.manage.mappers.riskbusiness.RiskMaterialMapper;
import au.com.royalpay.payment.manage.mappers.system.ClientMapper;
import au.com.royalpay.payment.manage.notice.core.MailService;
import au.com.royalpay.payment.manage.riskbusiness.core.RiskBusinessService;
import au.com.royalpay.payment.manage.riskbusiness.core.RiskUploadService;
import au.com.royalpay.payment.manage.riskbusiness.enums.RiskResultTypeEnum;
import au.com.royalpay.payment.tools.exceptions.BadRequestException;
import au.com.royalpay.payment.tools.threadpool.RoyalThreadPoolExecutor;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring4.SpringTemplateEngine;
import javax.annotation.Resource;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
@Service
public class RiskUploadServiceIpml implements RiskUploadService {
@Resource
private RiskMaterialMapper riskMaterialMapper;
@Resource
private RiskFileMapper riskFileMapper;
@Resource
private RiskEventMapper riskEventMapper;
@Resource
private StringRedisTemplate stringRedisTemplate;
private final String UPLOAD_MAIL_PREFIX = "UPLOAD_MAIL";
@Override
public void submitMaterial(JSONObject material) {
JSONObject event = riskEventMapper.findById(material.getString("risk_id"));
riskMaterialMapper.save(material);
material.put("material_id",riskMaterialMapper.findAllMaterials(material.getString("risk_id")).get(0).getString("material_id"));
for(int i=1;i<=10;i++){
if(material.containsKey("file"+i+"_url")){
List<String> urls = (List<String>)material.get("file"+i+"_url");
for(String url:urls){
JSONObject file = new JSONObject();
file.put("file_url",url);
file.put("file_type",i);
file.put("material_id",material.getString("material_id"));
riskFileMapper.save(file);
}
}
}
event.put("result_type", RiskResultTypeEnum.WAIT_FOR_AUDIT.getResultType());
riskEventMapper.update(event);
}
@Override
public void deleteUploadMailKey(String codeKey) {
stringRedisTemplate.delete(getRiskUploadKey(codeKey));
}
@Override
public void checkUploadMailKey(String codeKey,String risk_id) {
JSONObject event = riskEventMapper.findById(risk_id);
//到期日前一天的下午6点前url可用
try {
String reply = DateFormatUtils.format(DateUtils.addDays(event.getDate("reply_email_date"),-1),"yyyy-MM-dd 18:00:00");
if(new Date().after( DateUtils.parseDate(reply,new String[]{"yyyy-MM-dd HH:mm:ss"}))){
deleteUploadMailKey(codeKey);
throw new BadRequestException("Url expired");
}
} catch (ParseException e) {
e.printStackTrace();
}
if (StringUtils.isNotEmpty(codeKey)) {
String redisUpload = stringRedisTemplate.boundValueOps(getRiskUploadKey(codeKey)).get();
if (redisUpload == null) {
throw new BadRequestException("Url expired");
}
}
}
private String getRiskUploadKey(String codeKey){
return UPLOAD_MAIL_PREFIX + codeKey;
}
}

@ -0,0 +1,27 @@
package au.com.royalpay.payment.manage.riskbusiness.enums;
/**
* @Author lvjian
* @Date 2018/10/16 22:22
*/
public enum RiskEmailStatusEnum {
NOT_SEND(0),
ALREADY_SEND(1),
BACK_AND_SEND(2),
SEND_EMAIL_AGAIN(3),
;
private Integer emailStatus;
RiskEmailStatusEnum(Integer emailStatus) {
this.emailStatus = emailStatus;
}
public Integer getEmailStatus() {
return emailStatus;
}
public void setEmailStatus(Integer emailStatus) {
this.emailStatus = emailStatus;
}
}

@ -0,0 +1,29 @@
package au.com.royalpay.payment.manage.riskbusiness.enums;
/**
* @Author lvjian
* @Date 2018/10/16 20:18
*/
public enum RiskOrderTypeEnum {
WECHAT_ORDER(1),
ALIPAY_ORDER(2),
ROYALPAY_ORDER(3),
WARNING_ORDER(4),
GENERAL_ORDER(5)
;
private Integer orderType;
public Integer getOrderType() {
return orderType;
}
public void setOrderType(Integer orderType) {
this.orderType = orderType;
}
RiskOrderTypeEnum(Integer orderType) {
this.orderType = orderType;
}
}

@ -0,0 +1,29 @@
package au.com.royalpay.payment.manage.riskbusiness.enums;
/**
* @Author lvjian
* @Date 2018/10/16 20:40
*/
public enum RiskResultTypeEnum {
NOT_HANDLED(0),
SEND_EMAIL_TO_BD(1),
WAIT_FOR_AUDIT(2),
MATERIAL_AUDIT_PASS(3),
MATERIAL_NOT_PASS(4),
ALREADY_HANDLED(5);
private Integer resultType;
RiskResultTypeEnum(Integer resultType) {
this.resultType = resultType;
}
public Integer getResultType() {
return resultType;
}
public void setResultType(Integer resultType) {
this.resultType = resultType;
}
}

@ -1,28 +1,132 @@
package au.com.royalpay.payment.manage.riskbusiness.web;
import au.com.royalpay.payment.manage.merchants.beans.PartnerQuery;
import au.com.royalpay.payment.manage.merchants.core.ClientManager;
import au.com.royalpay.payment.manage.permission.manager.ManagerMapping;
import au.com.royalpay.payment.manage.riskbusiness.bean.RiskEventQuery;
import au.com.royalpay.payment.manage.riskbusiness.core.RiskBusinessService;
import au.com.royalpay.payment.manage.riskbusiness.enums.RiskResultTypeEnum;
import au.com.royalpay.payment.tools.CommonConsts;
import au.com.royalpay.payment.tools.permission.enums.ManagerRole;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.sun.org.apache.xerces.internal.impl.dv.xs.BooleanDV;
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
*
* @Author lvjian
* @Date 2018/10/10 1:12
*/
@RestController
@RequestMapping("/risk/business/")
@ManagerMapping(value = "/risk/business/", role = {ManagerRole.OPERATOR, ManagerRole.ADMIN, ManagerRole.BD_USER, ManagerRole.RISK_MANAGER})
public class RiskBusinessController {
@ManagerMapping(value = "event", method = RequestMethod.GET, role = {ManagerRole.OPERATOR, ManagerRole.ADMIN})
public String testHello() {
return "Hello";
@Autowired
private RiskBusinessService riskBusinessService;
@Autowired
private ClientManager clientManager;
@GetMapping(value = "events")
public JSONObject getRiskEvents(RiskEventQuery riskEventQuery, @ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
JSONObject params = riskEventQuery.toJSON();
return riskBusinessService.getRiskEventsByPage(params, manager);
}
@GetMapping(value = "events/{risk_id}")
public JSONObject getRiskEventDetail(@PathVariable("risk_id") String riskId,
@ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
JSONObject riskEvent = riskBusinessService.getRiskEventDetail(riskId);
List<JSONObject> tradeLogs = riskBusinessService.getRiskEventOrderList(riskEvent.getString("order_ids"));
riskEvent.put("tradeLogs", tradeLogs);
return riskEvent;
}
@PostMapping(value = "events")
public void RegisterRiskEvent(@RequestBody JSONObject params,
@ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
riskBusinessService.addRiskEvent(params, manager);
}
@PutMapping(value = "events")
public void UpdateRiskEvent(@RequestBody JSONObject params) {
riskBusinessService.updateRiskEvent(params);
}
@GetMapping(value = "/{risk_id}/download/materialsAsZIP")
public void downloadComplianceZip(@PathVariable("risk_id") String riskId, HttpServletResponse response) throws Exception {
riskBusinessService.downloadAuditMaterialZiP(riskId, response);
}
@RequestMapping(value = "/{risk_id}/upload_mail",method = RequestMethod.PUT)
public void uploadEmail(@PathVariable String risk_id) throws IOException {
riskBusinessService.sendUploadEmail(risk_id);
}
@RequestMapping(value = "/{risk_id}/refuse",method = RequestMethod.PUT)
public void refuseEmail(@PathVariable String risk_id) throws IOException {
riskBusinessService.sendRefuseEmail(risk_id);
}
@GetMapping(value = "/{risk_id}/material")
public JSONObject getRiskMaterial(@PathVariable("risk_id") String riskId) {
JSONObject param = new JSONObject();
param.put("risk_id", riskId);
return riskBusinessService.getRiskMaterial(param);
}
@PutMapping(value = "/channel/{channel}/permission/{channelFlag}")
public void updateMerchantChannel(@RequestBody JSONObject params,
@PathVariable("channelFlag") Boolean channelFlag,
@PathVariable("channel") String channel,
@ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
clientManager.switchChannelPermission(manager, params.getString("client_moniker"), channel, channelFlag);
if (channelFlag)
params.put("result_type", RiskResultTypeEnum.ALREADY_HANDLED.getResultType());
riskBusinessService.updateRiskEvent(params);
}
@PutMapping(value = "/partner/{isValid}")
public void updateMerchantValid(@RequestBody JSONObject params,
@PathVariable("isValid") Boolean isValid,
@ModelAttribute(CommonConsts.MANAGER_STATUS) JSONObject manager) {
String clientMoniker = params.getString("client_moniker");
if (isValid) {
clientManager.disableClient(clientMoniker, manager);
Integer temporaryCloseMerchant = params.getInteger("temporary_close_merchant");
if (temporaryCloseMerchant != 1) {
params.put("result_type", RiskResultTypeEnum.ALREADY_HANDLED.getResultType());
}
}
else {
clientManager.revertClient(clientMoniker, manager);
params.put("result_type", RiskResultTypeEnum.ALREADY_HANDLED.getResultType());
}
riskBusinessService.updateRiskEvent(params);
}
@RequestMapping(value = "/{risk_id}/urge",method = RequestMethod.PUT)
public void urgeEmail(@PathVariable String risk_id) throws IOException {
riskBusinessService.sendUrgeEmail(risk_id);
}
@ManagerMapping(value = "event/{risk_id}", method = RequestMethod.GET, role = {ManagerRole.OPERATOR, ManagerRole.ADMIN})
public JSONObject getRiskEventDetail() {
return null;
@GetMapping(value = "/partners")
public List<JSONObject> getPartners(PartnerQuery partnerQuery) {
JSONObject param = partnerQuery.toJsonParam();
return clientManager.getClientBySimpleQuery(param);
}
}

@ -0,0 +1,50 @@
package au.com.royalpay.payment.manage.riskbusiness.web;
import au.com.royalpay.payment.manage.riskbusiness.core.RiskBusinessService;
import au.com.royalpay.payment.manage.riskbusiness.core.RiskUploadService;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
@RestController
@RequestMapping("/risk/upload")
public class RiskFileUploadController {
@Resource
private RiskUploadService riskUploadService;
@Resource
private RiskBusinessService riskBusinessService;
/**
*
* @param codeKey
* @param risk_id
* @return
*/
@RequestMapping(value = "/{risk_id}/{codeKey}", method = RequestMethod.GET)
public ModelAndView jumpVerifyMail(@PathVariable String codeKey, @PathVariable String risk_id) {
//检查codekey是否有效
riskUploadService.checkUploadMailKey(codeKey,risk_id);
JSONObject event = riskBusinessService.getRiskEventDetail(risk_id);
ModelAndView view = new ModelAndView("mail/risk_upload");
view.addObject("codeKey", codeKey);
view.addObject("risk_id",risk_id);
view.addObject("order_type",event.getIntValue("order_type"));
view.addObject("short_name",event.getJSONObject("clientInfo").getString("short_name"));
return view;
}
/**
*
* @param codeKey
* @param material
*/
@RequestMapping(value = "/{codeKey}", method = RequestMethod.POST)
public void upload(@PathVariable String codeKey, @RequestBody JSONObject material) {
riskUploadService.checkUploadMailKey(codeKey, material.getString("risk_id"));
riskUploadService.submitMaterial(material);
riskUploadService.deleteUploadMailKey(codeKey);
}
}

@ -27,6 +27,10 @@ public class AttachmentController {
public JSONObject uploadImage(@RequestParam MultipartFile file) throws IOException {
return attachmentClient.uploadFile(file,false);
}
@RequestMapping(value = "/riskFiles", method = RequestMethod.POST)
public JSONObject uploadRiskImage(@RequestParam MultipartFile file) throws IOException {
return attachmentClient.uploadFile(file,false);
}
@RequestMapping(value = "/secret_files", method = RequestMethod.POST)
@RequirePartner

@ -1,6 +1,6 @@
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.schema-name=royalpay_production
spring.datasource.host=192.168.0.49:3306
spring.datasource.host=192.168.0.111:3306
spring.datasource.url=jdbc:mysql://${spring.datasource.host}/${spring.datasource.schema-name}?useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root

@ -738,6 +738,81 @@
<if test="clearing_status!=null">and t.clearing_status=#{clearing_status}</if>
</where>
</select>
<select id="findOrderById" resultType="com.alibaba.fastjson.JSONObject">
SELECT
o.order_id order_id,
o.currency,
o.channel,
o.create_time,
o.confirm_time pay_time,
format(o.total_amount,2) total_amount,
format(o.display_amount,2) display_amount,
format(o.refund_amount,2) refund_amount,
format(t.exchange_rate,6) exchange_rate,
CASE o.status
WHEN 0
THEN 'Creating'
WHEN 1
THEN 'Failed Create Order'
WHEN 2
THEN 'Wait For Payment'
WHEN 3
THEN 'Closed'
WHEN 4
THEN 'Payment Failed'
WHEN 5
THEN 'Payment Successful'
WHEN 6
THEN 'Partial Refund'
WHEN 7
THEN 'Full Refund'
END AS `status`,
CASE o.gateway
WHEN 0
THEN '线下扫码'
WHEN 1
THEN '线下扫码'
WHEN 2
THEN '商户静态码'
WHEN 3
THEN '线上网关'
WHEN 4
THEN 'JSAPI网关'
WHEN 5
THEN '线下网关'
WHEN 6
THEN '线下网关'
WHEN 7
THEN '商户静态码'
WHEN 8
THEN 'Mobile H5'
WHEN 9
THEN '第三方网关'
WHEN 10
THEN 'APP网关'
WHEN 11
THEN '账单码'
WHEN 12
THEN '小程序'
WHEN 13
THEN '原生二维码'
WHEN 14
THEN '账单链接'
END AS gateway,
p.client_moniker partner_code,
p.short_name partner_name,
format(t.clearing_amount,2) clearing_amount
FROM pmt_orders o
INNER JOIN sys_clients p
ON p.client_id = o.client_id
LEFT JOIN pmt_transactions t
ON t.order_id = o.order_id
AND t.refund_id IS NULL
AND t.transaction_type = 'Credit'
AND t.channel != 'System'
WHERE o.order_id = #{order_id}
</select>
<select id="listHalloweenActOrder" resultType="com.alibaba.fastjson.JSONObject">
<![CDATA[
SELECT

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="au.com.royalpay.payment.manage.mappers.riskbusiness.RiskEventMapper">
<select id="listRisksByPage" resultType="com.alibaba.fastjson.JSONObject">
SELECT
re.risk_id,
re.client_moniker,
re.order_ids,
re.order_type,
re.royalpay_order_type,
re.warning_order_type,
re.description,
re.email_status,
re.receive_email_date,
re.reply_email_date,
re.fillin_person,
re.fillin_id,
re.result_type,
re.channel_result,
re.temporary_close_channel,
re.temporary_close_merchant,
re.in_merchant_blacklist,
re.in_user_blacklist,
re.processed_remark,
re.create_time,
sc.industry,
sc.short_name,
IFNULL(sc.sub_merchant_id, re.sub_merchant_id) sub_merchant_id
FROM risk_event re
LEFT JOIN sys_clients sc
ON re.client_moniker = sc.client_moniker
<if test="start_amount != null || end_amount != null">
RIGHT JOIN(
SELECT distinct re.risk_id
FROM
risk_event re,
risk_event_help reh
<where>
reh.risk_event_help_id &lt; (LENGTH(re.order_amounts) - LENGTH(REPLACE(re.order_amounts, ',' , ''))) + 1
<if test="start_amount != null">
AND cast(SUBSTRING_INDEX(SUBSTRING_INDEX(order_amounts,',',reh.risk_event_help_id + 1),',',-1) as signed) &gt;= #{start_amount}
</if>
<if test="end_amount != null">
AND cast(SUBSTRING_INDEX(SUBSTRING_INDEX(order_amounts,',',reh.risk_event_help_id + 1),',',-1) as signed) &lt;= #{end_amount}
</if>
</where>
) temp
on re.risk_id = temp.risk_id
</if>
<if test="bd_id != null">
LEFT JOIN(
SELECT DISTINCT client_id
FROM sys_client_bd
WHERE
is_valid = 1
AND bd_id = #{bd_id}
AND end_date &gt; NOW()
) scb
ON sc.client_id = scb.client_id
</if>
<where>
<if test="risk_id != null">
AND re.risk_id = #{risk_id}
</if>
<if test="client_moniker != null">
AND re.client_moniker = #{client_moniker}
</if>
<if test="order_types != null">
<foreach collection="order_types" item="order_type_item" open="and re.order_type in (" close=")" separator=",">
#{order_type_item}
</foreach>
</if>
<if test="order_type != null">
AND re.order_type = #{order_type}
</if>
<if test="result_types != null">
<foreach collection="result_types" item="result_type_item" open="AND re.result_type IN (" close=")" separator=",">
#{result_type_item}
</foreach>
</if>
<if test="result_type != null">
AND re.result_type = #{result_type}
</if>
<if test="order_ids != null">
AND re.order_ids LIKE CONCAT('%', #{order_ids}, '%')
</if>
<if test="sub_merchant_id != null">
AND sc.sub_merchant_id = #{sub_merchant_id}
</if>
<if test="industry != null">
AND sc.industry = #{industry}
</if>
<if test="receive_email_date != null">
AND re.receive_email_date = #{receive_email_date}
</if>
<if test="reply_email_date != null">
AND re.reply_email_date = #{reply_email_date}
</if>
</where>
</select>
</mapper>

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="au.com.royalpay.payment.manage.mappers.riskbusiness.RiskMaterialMapper">
<select id="findOperatorById" resultType="com.alibaba.fastjson.JSONObject">
SELECT m.*
FROM risk_material r
LEFT JOIN risk_event e
ON r.risk_id = e.risk_id
LEFT JOIN sys_managers m
ON e.fillin_id = m.manager_id
WHERE r.risk_id = #{risk_id}
LIMIT 1
</select>
<select id="findAllMaterials" resultType="com.alibaba.fastjson.JSONObject">
SELECT *
FROM risk_material
WHERE risk_id = #{risk_id}
ORDER BY update_time DESC
</select>
</mapper>

@ -41,11 +41,29 @@
<![CDATA[
SELECT m.*
FROM sys_managers m
INNER JOIN sys_client_bd b ON b.bd_id = m.manager_id
WHERE client_id = #{client_id} AND start_date <= #{date} AND (end_date > #{date} OR end_date IS NULL) AND
b.is_valid = 1
INNER JOIN sys_client_bd b
ON b.bd_id = m.manager_id
WHERE client_id = #{client_id}
AND start_date <= #{date}
AND (end_date > #{date} OR end_date IS NULL)
AND b.is_valid = 1
]]>
</select>
<!--找出BD管理的商户-->
<select id="listBDClientInfo" resultType="com.alibaba.fastjson.JSONObject">
<![CDATA[
SELECT sc.*
FROM sys_client_bd scb
INNER JOIN sys_clients sc
ON scb.client_id = sc.client_id
WHERE scb.bd_id = #{bd_id}
AND scb.start_date <= #{date}
AND (scb.end_date > #{date} OR scb.end_date IS NULL)
AND scb.is_valid = 1
]]>
</select>
<select id="findTheMaxBDCommissionEndDate" resultType="java.util.Date">
SELECT MAX(end_date)
FROM sys_client_bd

@ -83,9 +83,12 @@ todo.settlement.date_setting=Settle Dates configured are running out. Config new
todo.rate.expire_warning=Some clients' rate are expiring soon or expired. Please fix it as soon as possible.
todo.client.approve=Some clients are waiting for compliance.
todo.client.greenchannel=The data of Some clients in Green channel are waiting for committing.
todo.bd.order=The merchant managed by you is transferred. Please submit the materials as soon as possible.
app.message.title.payment=Payment Message
app.message.body.payment=You have received a payment of
app.message.title.risk=Risk Control Message
app.message.body.risk=You have received a risk control reminder. Please check the email for details.
app.message.title.notice=System Message
app.message.body.refund=Your refund request has bean sent,refund count is
app.message.body.cashback=You got a cashback of

@ -79,9 +79,12 @@ todo.settlement.date_setting=已配置清算日即将到期,请配置新的清
todo.rate.expire_warning=有商户费率即将到期或已过期,请尽快处理
todo.client.approve=有等待审核的商户
todo.client.greenchannel=有绿色通道商户等待提交资料
todo.bd.order=有商户被调单,请尽快提交材料
app.message.title.payment=到账通知
app.message.body.payment=您有一笔新的到账,
app.message.title.risk=风控通知
app.message.body.risk=您收到了一条风控提醒,详情请查看邮件
app.message.title.notice=系统通知
app.message.body.refund=退款申请已提交渠道方处理,退款金额
app.message.body.cashback=您获得了一笔ROYALPAY返现金额

@ -0,0 +1,24 @@
<html xmlns:th="http://www.thymeleaf.org" lang="zh">
<h4>Dear <span th:text="${operator}"></span> :</h4>
<p>您好,您于<span th:text="${create_time}"></span>创建的风控事件单已经接收到了商户<span th:text="${short_name}"></span>(<span th:text="${client_moniker}"></span>)的风控材料,请及时审核。</p>
<h4>Best Regards</h4>
<p>
<img style="width: 120px;height: 120px"
src="https://mpay.royalpay.com.au/static/images/logo_new.jpg"> <br>
Contact Us<br>
Email:<br>
<a href="mailto:info@royalpay.com.au">info@royalpay.com.au</a> <br>
Tel:<br>
1300 10 77 50<br>
<br>
Service WeChat Account:<br>
<img src="https://mpay.royalpay.com.au/static/images/customer_service.jpg"
style="width: 60px"><br>
Level 14, 383 Kent Street, Sydney NSW 2000<br>
<br>
Level 11, 15 William Street, Melbourne VIC 3000
</p>
<p>Tunnel Show Pty Ltd trading as RoyalPay<br>
Representative of AFSL licensee 448066
</p>
</html>

@ -0,0 +1,463 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" user-scalable="no">
<title>RoyalPay | Risk Materials</title>
<meta name="description"
content=" As Australias first WeChat Cross-Border payment gatewayWe are working to build a bridge between Australian merchants and Chinese consumers.Marketing Tools like WeChat Coupons,Membership Cards,Lucky Money are provided to all merchants to Increase sales which is proved effective in the wechat ecology.">
<meta name="keywords"
content="澳洲微信支付、澳洲跨境支付、行业解决方案、澳洲支付、澳洲商圈、微信营销、公众号、Wechat、Official Account、Industry Solution、Cross-Border Payment、Australia Wechat">
<!-- Bootstrap 3.3.5 -->
<link href="/static/css/merchant_application.css" rel="stylesheet">
<link href="/static/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="/static/lib/font-awesome-4.6.3/css/font-awesome.min.css" rel="stylesheet">
<!-- Font Awesome -->
<!-- Ionicons -->
<!-- Theme style -->
<link rel="stylesheet" href="/static/css/index_register.css">
<link rel="stylesheet" href="/static/lib/dist/css/AdminLTE.min.css">
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<script type="text/javascript" src="/static/lib/jquery/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="/static/lib/angularjs/angular.min.js"></script>
<script type="text/javascript" src="/static/lib/angularjs/angular-messages.js"></script>
<script type="text/javascript" src="/static/lib/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/static/riskupload/risk_upload.js"></script>
<script type="text/javascript" src="/static/lib/ngfileupload/ng-file-upload.min.js"></script>
<script type="text/javascript" src="/static/lib/angular-plugins/ui-bootstrap-tpls-2.5.0.min.js"></script>
<style type="text/css">
.register-box-bg {
background-color: rgba(255, 255, 255, 0.9);
box-shadow: 0px 2px 20px 2px rgba(0, 0, 0, 0.3);
filter: alpha(opacity=40);
/*opacity: 0.7;*/
}
@media (min-width: 544px) {
.content-with {
width: 800px;
}
.register-box {
margin-top: 10%;
}
body .progress {
display: block;
}
body .step_show {
display: none;
}
.button_width{
width: 20%;
}
.input-group .form-control{
position: relative;
z-index: 2;
float: left;
width: 80%;
margin-bottom: 0;
}
}
@media (max-width: 544px) {
body .progress {
display: none;
}
.content_align{
width: 80%;
}
body .step_show {
display: block;
}
.button_width{
width: 35%;
}
.input-group .form-control{
position: relative;
z-index: 2;
float: left;
width: 65%;
margin-bottom: 0;
}
.register-box {
width: 89%;
}
}
@media (max-width: 544px) {
.logo-width {
width: 50%;
}
}
</style>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?d7e727bd889ea69d369cba051844dfe5";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body class="pace-done fp-viewing-0" ng-app="riskUploadApp" ng-controller="riskUploadCtrl">
<!--[if lte IE 8]>
<span class="lower-ie"></span>
<![endif]-->
<div class="pace pace-inactive">
<div class="pace-progress" data-progress-text="100%" data-progress="99"
style="transform: translate3d(100%, 0px, 0px);">
<div class="pace-progress-inner"></div>
</div>
<div class="pace-activity"></div>
</div>
<div id="main">
<div id="page-index" class="register-page">
<nav id="header" class="navbar navbar-dark navbar-full navbar-bg">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse"
data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="https://www.royalpay.com.au/">
<img src="/static/images/logo.svg" alt="" class="navbar--logo"
style="width: 275px;height: 32px;display: block;margin-top: 3.2%;">
</a>
</div>
<ul class="nav navbar-nav navbar-right navbar-collapse collapse">
<li id="nav-index" class="nav-item">
<a href="https://www.royalpay.com.au/" class="nav-link">Home</a>
</li>
<li class="nav-item dropdown">
<a role="button" class="nav-link dropdown-toggle" data-toggle="dropdown">Wechat</a>
<ul class="dropdown-menu">
<li><a href="https://www.royalpay.com.au/feature.html" target="_blank">Features</a></li>
<li><a href="https://www.royalpay.com.au/industry.html" target="_blank">Industry</a></li>
<li><a href="https://www.royalpay.com.au/marketing.html" target="_blank">Marketing</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a role="button" class="nav-link dropdown-toggle" data-toggle="dropdown">GATEWAY API</a>
<ul class="dropdown-menu">
<li><a href="https://mpay.royalpay.com.au/docs/en/" target="_blank">En</a></li>
<li><a href="https://mpay.royalpay.com.au/docs/cn/" target="_blank">中文</a></li>
</ul>
</li>
<li class="nav-item">
<a role="button" class="nav-link dropdown-toggle" data-toggle="dropdown">About Us</a>
<ul class="dropdown-menu">
<li><a href="https://www.royalpay.com.au/about.html" target="_blank">About Us</a></li>
<li><a href="https://www.royalpay.com.au/c_news.html">News</a></li>
<li><a href="https://www.royalpay.com.au/c_career.html">Career</a></li>
</ul>
</li>
<li class="nav-item">
<a href="https://www.royalpay.com.au/download.html" class="nav-link">App</a>
</li>
<li class="nav-item hidden-xs hidden-sm">
<a href="https://mpay.royalpay.com.au/login.html" target="_blank"
class="btn btn-success signin">Sign In</a>
</li>
<li class="nav-item hidden-xs hidden-sm">
<a href="https://mpay.royalpay.com.au/partner_register.html" target="_blank"
class="btn btn-success signin">Apply</a>
</li>
</ul>
</div>
</nav>
<div id="fullpage" class="fullpage-wrapper">
<div class="register-box content-with" style="margin-top:4%">
<div class="register-box-body register-box-bg">
<p class="login-box-msg">Easy BusinessEasy Payment</p>
<p class="small text-info" id="short_name"></p>
<form novalidate name="uploadForm">
<div class="panel-body">
<div class="form-horizontal">
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="order_type==1">1、物流公司发货单据照片
要求:每笔交易对应的物流单必须提供,且单据必须清晰可见<br>
Photos of logistics companies goods-delivery documents
Requirement: The logistics order record corresponding to each transaction must be provided, and details of records should be clearly visible.
</p>
<p ng-if="order_type==3">1.请解释相应的消费场景/业务模式,例如网站商城,扫码支付, 消费者到店支付等;<br>
Please explain the relative payment scenario/business activities, for example, online store, QR code payment, payment at the store, etc;
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile1($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file1Progress.value" type="success" animate="true" ng-if="file1Progress.value" max="100"
>{{file1Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file1_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="order_type==1">2、用户购买虚拟物品需要提供聊天记录、订单信息、发货凭证截图、虚拟物品最终消费场景例如何种游戏、软件、提供消费场景网址/下载链接
要求:每笔交易对应的截图必须清晰可见<br>
Users need to provide chat records, order information, screenshots of delivery documents, final consumption scenarios of virtual goods (such as games, software); provide consumer scene URL / download link.
Requirement: The screenshot corresponding to each transaction must be clearly visible.
</p>
<p ng-if="order_type==3">2.提供相应购物清单,订单小票(请提供与被查交易订单号相匹配的交易时间及金额的发票);<br>
Provide related shopping lists, invoices. (Please provide the invoices, amount of which matches that of the abnormal transaction);
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile2($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file2Progress.value" type="success" animate="true" ng-if="file2Progress.value" max="100"
>{{file2Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file2_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="order_type==1">3、购物小票/发票存根照片
照片应清晰,必须显示商户名称、商户地址、购物时间、物品名称
购物金额等<br>
Photos of shopping receipts/ invoice stubs
Requirement: The photos should be clear and must show Merchant name, Business address, Transaction time, Product information, Quantity purchased, etc.
</p>
<p ng-if="order_type==3">3.提供相应的发货证明,报关单(若有消费者在国内购买,请提供物流单据或报关单);<br>
Relative proof of delivery, customs declaration (If the consumer purchased from China, please provide shipping receipt or customs declaration);
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile3($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file3Progress.value" type="success" animate="true" ng-if="file3Progress.value" max="100"
>{{file3Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file3_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="order_type==1">4、显示商户门牌号码和店头名称的照片
要求:清晰可见,至少一张<br>
Photos of Merchant Street number & Merchant name
Requirement: At least one visible photo
</p>
<p ng-if="order_type==3">4.提供您的门店照片(门店照及店铺内的照片各一张, 一张可以看到商户名的门头照,一张可以看到相关商品或服务的店内照片);<br>
Photos of the store ( one of each front-store and in-store);
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile4($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file4Progress.value" type="success" animate="true" ng-if="file4Progress.value" max="100"
>{{file4Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file4_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="order_type==1">5、显示商户营业场景所场内部情况如店内商品陈列、收银台等的照片
要求:照片清晰,且能清楚显示商户实际售卖物品或服务,至少三张<br>
Photos of internal environment of merchant business (such as in-store merchandise display, checkout counter, etc.)
Requirements: The photos (at least three) showing merchant activities including actual selling-goods or services obviously
</p>
<p ng-if="order_type==3">5.其他可以还原交易背景的资料,如和消费者的聊天记录等,来佐证被查单号交易的真实性;<br>
Other materials that can verify the payment scenario, for example, chatting history, to prove the truth of the transactions;
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile5($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file5Progress.value" type="success" animate="true" ng-if="file5Progress.value" max="100"
>{{file5Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file5_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p>6、其他图片<br>
Other pictures
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile6($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file6Progress.value" type="success" animate="true" ng-if="file6Progress.value" max="100"
>{{file6Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file6_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Description</label>
<div class="col-sm-10">
<textarea class="form-control" required
ng-model="material.description" placeholder="No more than 500"
name="description"
maxlength="500"></textarea>
<input id="codeKey" type="text" class="hidden" name="codeKey"
ng-model="codeKey">
<input id="risk_id" type="text" class="hidden" name="risk_id"
ng_model="material.risk_id">
<input id="order_type" type="text" class="hidden" name="order_type"
ng_model="order_type">
</div>
</div>
</div>
</div>
</form>
<div style="text-align: center">
<a role="button" style="margin-bottom: 25px;" class="btn btn-success btn-sm ng-scope" ng-disabled="!(material.description)"
ng-click="submit(uploadForm)">Submit</a>
</div>
</div>
</div>
<script type="text/javascript" data-th-inline="javascript">
$(document).ready(function () {
window.codeKey = /*[[${codeKey}]]*/'';
window.risk_id = /*[[${risk_id}]]*/'';
window.order_type = /*[[${order_type}]]*/'';
window.short_name = /*[[${short_name}]]*/'';
$('#codeKey').val(window.codeKey).trigger('input');
$('#risk_id').val(window.risk_id).trigger('input');
$('#order_type').val(window.order_type).trigger('input');
$('#short_name').text(window.short_name);
})
</script>
</div>
<section class="section section-six fp-auto-height footer">
<div class="container">
<div class="row margin-bottom">
<div class="col-md-4 footer-item">
CONTACT US
<hr>
Level 14<br>
383 Kent Street<br>
Sydney NSW 2000<br>
<br>
Level 11<br>
15 William Street<br>
Melbourne VIC 3000<br>
<br>
1300-10-77-50<br>
03 9448 8865<br>
info@royalpay.com.au
</div>
<div class="col-md-4 sitemap footer-item">
SITE MAP
<hr>
<div class="row">
<div class="col-xs-6">
<p><a href="/">RoyalPay</a></p>
<p><a href="https://mpay.royalpay.com.au/docs/en/">Gateway API</a></p>
<p><a href="https://www.royalpay.com.au/industry.html">Industry Solution</a></p>
<p><a href="https://www.royalpay.com.au/marketing.html">Marketing Service</a></p>
</div>
<div class="col-xs-6">
<p><a href="https://www.royalpay.com.au/about.html">About Us</a></p>
<p><a href="https://www.royalpay.com.au/c_news.html">News</a></p>
<p><a href="https://www.royalpay.com.au/c_career.html">Career</a></p>
<p><a href="https://www.royalpay.com.au/download.html">Downloads</a></p>
</div>
</div>
</div>
<div class="col-md-4 footer-item">
SUPPORT
<hr>
<div class="row">
<div class="col-xs-6 qr-box">
<img src="/static/css/img/qr_royalpay.png">
RoyalPay WeChat Official Account
</div>
<div class="col-xs-6 qr-box">
<img src="/static/css/img/qr_service.png">
Customer Service
</div>
</div>
</div>
</div>
</div>
<div class="copyright">
<div class="container">
<div class="row">
<div class="col-xs-12 text-center">
© 2016 Tunnel Show Pty. Ltd. | Representative of AFSL licensee 448066
</div>
</div>
</div>
</div>
</section>
</div>
</div>
</div>
<div id="fp-nav" class="right"></div>
<div id="cli_dialog_div"></div>
</body>
</html>

@ -0,0 +1,94 @@
<html xmlns:th="http://www.thymeleaf.org" lang="zh">
<div th:if="${order_type==1||order_type==2}">
<b>Dear <span th:text="${bdNamesStr}"></span> :</b>
<p>您好<span th:if="${refuse}">,您提交的风控材料已被拒绝</span>。请于<span th:text="${reply_date}"></span>下午6:00悉尼时间前提供被查商户<span th:text="${client.short_name}"></span> (<span th:text="${client.client_moniker}"></span>)的以下材料</p>
<p>请提供以下被查单号的小票, 物流单据(如有邮寄产品的情况), 以及消费者与买家的聊天记录等来佐证被查交易单号。 被查交易单号如下:</p>
<table style="border: 1.0px solid;border-collapse: collapse;">
<thead>
<tr>
<th style="border: 1.0px solid;border-collapse: collapse;">Order ID</th>
<th style="border: 1.0px solid;border-collapse: collapse;">Amount</th>
<th style="border: 1.0px solid;border-collapse: collapse;">Input Amount</th>
<th style="border: 1.0px solid;border-collapse: collapse;">AUD Amount</th>
<th style="border: 1.0px solid;border-collapse: collapse;">Exchange Rate</th>
<th style="border: 1.0px solid;border-collapse: collapse;">Status</th>
<th style="border: 1.0px solid;border-collapse: collapse;">Create Time</th>
<th style="border: 1.0px solid;border-collapse: collapse;">Gateway</th>
</tr>
</thead>
<tbody>
<tr th:each="order : ${orders}">
<td th:text="${order.order_id}" style="border: 1.0px solid;border-collapse: collapse;"></td>
<td th:text="${order.currency}+${order.total_amount}" style="border: 1.0px solid;border-collapse: collapse;"></td>
<td th:text="${order.currency}+${order.display_amount}" style="border: 1.0px solid;border-collapse: collapse;"></td>
<td th:text="AUD+${order.clearing_amount}" style="border: 1.0px solid;border-collapse: collapse;"></td>
<td th:text="${order.exchange_rate}" style="border: 1.0px solid;border-collapse: collapse;"></td>
<td th:text="${order.status}" style="border: 1.0px solid;border-collapse: collapse;"></td>
<td th:text="${order.create_time}" style="border: 1.0px solid;border-collapse: collapse;"></td>
<td th:text="${order.gateway}" style="border: 1.0px solid;border-collapse: collapse;"></td>
</tr>
</tbody>
</table>
<p>如果提交的材料不齐, 则有关停支付的风险。还请按时提供商户材料并直接回复该邮件, 感谢,辛苦。</p>
<!--<p>请点击此链接上传所需材料<a th:href="${uploadUrl}"><span th:text="${uploadUrl}"></span></a></p>-->
<p><a th:href="${uploadUrl}" style="color: rgb(255, 255, 255); text-align: center; padding: 12px 10px; height: 100%; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; text-decoration: none; background-color: #00c0ef; min-width: 150px;"><strong>Submit Risk Materials</strong></a></p>
</div>
<div th:if="${order_type==3}">
<b>尊敬的RoyalPay商户 :<br>
Dear RoyalPay merchant :</b>
<p th:if="${refuse}" style="background-color: #dd0000">您提交的风控材料已被拒绝。<br>
The risk materials you submitted has been rejected
</p>
<p>近期由于我们的风控系统检测到您的交易异常<span th:if="${royalpay_order_type==1}" style="background: #FCE824">已暂时将您的清算周期调整为T+<span th:text="${client.clean_days}"></span></span>,还请您提供以下材料,还原附件中列明的交易的真实背景:<br>
RoyalPay's risk management system recently has identified abnormal transactions from your records<span th:if="${royalpay_order_type==1}" style="background: #FCE824">, clean days has been adjusted to T+<span th:text="${client.clean_days}"></span></span>.so please provide us with following materials to assist in verifying the real scenario of the transactions attached:</p>
<p>1.请解释相应的消费场景/业务模式,例如网站商城,扫码支付, 消费者到店支付等;<br>
&nbsp;&nbsp;Please explain the relative payment scenario/business activities, for example, online store, QR code payment, payment at the store, etc;</p>
<p>2.提供相应购物清单,订单小票(请提供与被查交易订单号相匹配的交易时间及金额的发票);<br> 
&nbsp;&nbsp;Provide related shopping lists, invoices. (Please provide the invoices, amount of which matches that of the abnormal transaction);</p>
<p>3.提供相应的发货证明,报关单(若有消费者在国内购买,请提供物流单据或报关单);<br>
&nbsp;&nbsp;Relative proof of delivery, customs declaration (If the consumer purchased from China, please provide shipping receipt or customs declaration);</p>
<p>4.提供您的门店照片(门店照及店铺内的照片各一张, 一张可以看到商户名的门头照,一张可以看到相关商品或服务的店内照片);<br>
  &nbsp;&nbsp;Photos of the store ( one of each front-store and in-store);</p>
<p>5.其他可以还原交易背景的资料,如和消费者的聊天记录等,来佐证被查单号交易的真实性;<br>
&nbsp;&nbsp;Other materials that can verify the payment scenario, for example, chatting history, to prove the truth of the transactions;</p>
<p>注:以上证件需原件扫描件/数码拍摄件,且照片内容需真实有效,不得做任何修改。 </p>
<p>请查收附件中关于被抽查的订单交易的相关信息,并在<span style="background: #FCE824"><span th:text="${reply_date}"></span>下午600 (悉尼时间)前</span>将所需材料直接回复该邮件,未能按时提交完整证明材料,支付渠道将被关停,请您务必配合调查。感谢。<br>
Please find sampled transactions in attachment, and reply required materials to this email <span style="background: #FCE824">before 6:00 pm <span th:text="${reply_date_english}"></span> (AEST).</span> If you can not provide qualified materials on time, the payment channels would be suspended or restricted with amount limit. Please be sure to assist the investigation. Thanks.</p>
<!--<p>请点击此链接上传所需材料。<a th:href="${uploadUrl}"><span th:text="${uploadUrl}"></span></a><br>-->
<!--Please click on this link to upload the required materials.<a th:href="${uploadUrl}"><span th:text="${uploadUrl}"></span></a>-->
<!--</p>-->
<p><a th:href="${uploadUrl}" style="color: rgb(255, 255, 255); text-align: center; padding: 12px 10px; height: 100%; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; text-decoration: none; background-color: #00c0ef; min-width: 150px;"><strong>Submit Risk Materials</strong></a></p>
</div>
<div th:if="${order_type==4}">
<b>尊敬的RoyalPay商户 :<br>
Dear RoyalPay merchant :</b>
<p>我司风控系统检测到您短期内后台交易存在异常行为(<span th:if="${warning_order_type==0}" style="background: #FCE824">单人多次大金额交易</span><span th:if="${warning_order_type==1}" style="background: #FCE824">退款频繁</span>),触发平台风控预警,特此提醒:请勿使用平台进行违规交易,一经核查将关闭支付权限。请知悉。<br>
RoyalPay's risk management system has identified abnormal transactions from your records in a short time(<span th:if="${warning_order_type==0}" style="background: #FCE824">Single person pays large sums several times</span><span th:if="${warning_order_type==1}" style="background: #FCE824">frequent refund transactions</span>),which triggered the platform risk control warning. Here reminds: Do not use the platform for illegal transactions. Once verified, the payment authority will be closed. </p>
</div>
<p>顺颂商祺<br>
Sincerely
</p>
<p>
RoyalPay 风控团队<br>
RoyalPay Risk Management Team
</p>
<p>
<img style="width: 120px;height: 120px"
src="https://mpay.royalpay.com.au/static/images/logo_new.jpg"> <br>
Contact Us<br>
Email:<br>
<a href="mailto:info@royalpay.com.au">info@royalpay.com.au</a> <br>
Tel:<br>
1300 10 77 50<br>
<br>
Service WeChat Account:<br>
<img src="https://mpay.royalpay.com.au/static/images/customer_service.jpg"
style="width: 60px"><br>
Level 14, 383 Kent Street, Sydney NSW 2000<br>
<br>
Level 11, 15 William Street, Melbourne VIC 3000
</p>
<p>Tunnel Show Pty Ltd trading as RoyalPay<br>
Representative of AFSL licensee 448066
</p>
</html>

@ -0,0 +1,25 @@
<html xmlns:th="http://www.thymeleaf.org" lang="zh">
<b>Dear RoyalPay Merchant/BD :</b>
<p>您好,您的风控材料链接即将过期,请及时提交风控材料。未能按时提交完整证明材料,支付渠道将被关停,请您务必配合调查。感谢。</p>
<p>Your link to the risk materials is about to expire, please submit the risk materials in time.If you can not provide qualified materials on time, the payment channels would be suspended or restricted with amount limit. Please be sure to assist the investigation. Thanks.</p>
<h4>Best Regards</h4>
<p>
<img style="width: 120px;height: 120px"
src="https://mpay.royalpay.com.au/static/images/logo_new.jpg"> <br>
Contact Us<br>
Email:<br>
<a href="mailto:info@royalpay.com.au">info@royalpay.com.au</a> <br>
Tel:<br>
1300 10 77 50<br>
<br>
Service WeChat Account:<br>
<img src="https://mpay.royalpay.com.au/static/images/customer_service.jpg"
style="width: 60px"><br>
Level 14, 383 Kent Street, Sydney NSW 2000<br>
<br>
Level 11, 15 William Street, Melbourne VIC 3000
</p>
<p>Tunnel Show Pty Ltd trading as RoyalPay<br>
Representative of AFSL licensee 448066
</p>
</html>

@ -0,0 +1,190 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1" user-scalable="no">
<meta name="description" content="">
<title>Risk Materials | Success</title>
<link href="static/lib/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="static/lib/font-awesome-4.6.3/css/font-awesome.min.css" rel="stylesheet">
<link rel="stylesheet" href="./static/css/index_register.css">
<link rel="stylesheet" href="static/lib/dist/css/AdminLTE.min.css">
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<script type="text/javascript" src="/static/lib/jquery/jquery-2.1.4.min.js"></script>
<script type="text/javascript" src="/static/lib/angularjs/angular.min.js"></script>
<script type="text/javascript" src="/static/lib/angularjs/angular-messages.js"></script>
<script type="text/javascript" src="/static/lib/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/static/lib/blocs.min.js"></script>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?d7e727bd889ea69d369cba051844dfe5";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</head>
<body class="pace-done fp-viewing-0">
<!--[if lte IE 8]>
<span class="lower-ie"></span>
<![endif]-->
<div class="pace pace-inactive">
<div class="pace-progress" data-progress-text="100%" data-progress="99"
style="transform: translate3d(100%, 0px, 0px);">
<div class="pace-progress-inner"></div>
</div>
<div class="pace-activity"></div>
</div>
<div id="main">
<div id="page-index">
<nav id="header" class="navbar navbar-dark navbar-full navbar-fixed-top navbar-bg" style="position: absolute">
<div class="container">
<div class="navbar-header">
<button class="navbar-toggle collapsed" type="button" data-toggle="collapse"
data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="https://www.royalpay.com.au/">
<img src="static/css/img/logo_w.png" alt="" class="navbar--logo">
</a>
<span class="navbar-brand" style="margin-left: 10px;padding-left: 10px;border-left: 1px solid #fff;">
<img src="static/css/img/wechatpay.png" class="navbar--logo" style="transform: translateY(50%);height: 60%;">
</span>
</div>
<ul class="nav navbar-nav navbar-right navbar-collapse collapse">
<li id="nav-index" class="nav-item">
<a href="https://www.royalpay.com.au/index.html" class="nav-link">Home</a>
</li>
<li class="nav-item dropdown">
<a role="button" class="nav-link dropdown-toggle" data-toggle="dropdown">GATEWAY API</a>
<ul class="dropdown-menu">
<li><a href="https://mpay.royalpay.com.au/docs/en/" target="_blank">En</a></li>
<li><a href="https://mpay.royalpay.com.au/docs/cn/" target="_blank">中文</a></li>
</ul>
</li>
<li class="nav-item">
<a href="https://www.royalpay.com.au/industry.html" class="nav-link">Industry</a>
</li>
<li class="nav-item">
<a href="https://www.royalpay.com.au/marketing.html" class="nav-link">Marketing</a>
</li>
<li class="nav-item">
<a role="button" class="nav-link dropdown-toggle" data-toggle="dropdown">About Us</a>
<ul class="dropdown-menu">
<li><a href="https://www.royalpay.com.au/industry.html" target="_blank">About Us</a></li>
<li><a href="https://www.royalpay.com.au/c_news.html">News</a></li>
<li><a href="https://www.royalpay.com.au/c_career.html">Career</a></li>
</ul>
</li>
<li class="nav-item">
<a href="https://www.royalpay.com.au/download.html" class="nav-link">Downloads</a>
</li>
<li class="nav-item">
<a href="https://mpay.royalpay.com.au/login.html" target="_blank" class="nav-link">Sign In</a>
</li>
</ul>
</div>
</nav>
<div id="fullpage" class="fullpage-wrapper">
<section class="section section-industry"></section>
<section class="section section-two" style="padding-bottom: 50px;">
<div class="container">
<div class="container">
<!--<div class="row">-->
<!--<div class="col-sm-12">-->
<!--</div>-->
<!--</div>-->
<section class="content-header" style="text-align: center">
<img src="static/images/pay_success.png" style="width: 120px">
<h3>We have received your materials, our risk manager will review soon,</h3>
<h3>please wait for result.</h3>
</section>
</div>
</div>
</section>
<section class="section section-six fp-auto-height footer">
<div class="container">
<div class="row margin-bottom">
<div class="col-md-4 footer-item">
CONTACT US
<hr>
Level 14<br>
383 Kent Street<br>
Sydney NSW 2000<br>
<br>
Level 11<br>
15 William Street<br>
Melbourne VIC 3000<br>
<br>
1300-10-77-50<br>
03 9448 8865<br>
info@royalpay.com.au
</div>
<div class="col-md-4 sitemap footer-item">
SITE MAP
<hr>
<div class="row">
<div class="col-xs-6">
<p><a href="/">RoyalPay</a></p>
<p><a href="https://mpay.royalpay.com.au/docs/en/">Gateway API</a></p>
<p><a href="https://www.royalpay.com.au/industry.html">Industry Solution</a></p>
<p><a href="https://www.royalpay.com.au/marketing.html">Marketing Service</a></p>
</div>
<div class="col-xs-6">
<p><a href="https://www.royalpay.com.au/about.html">About Us</a></p>
<p><a href="https://www.royalpay.com.au/c_news.html">News</a></p>
<p><a href="https://www.royalpay.com.au/c_career.html">Career</a></p>
<p><a href="https://www.royalpay.com.au/download.html">Downloads</a></p>
</div>
</div>
</div>
<div class="col-md-4 footer-item">
SUPPORT
<hr>
<div class="row">
<div class="col-xs-6 qr-box">
<img src="static/css/img/qr_royalpay.png">
RoyalPay WeChat Official Account
</div>
<div class="col-xs-6 qr-box">
<img src="static/css/img/qr_service.png">
Customer Service
</div>
</div>
</div>
</div>
</div>
<div class="copyright">
<div class="container">
<div class="row">
<div class="col-xs-12 text-center">
© 2016 Tunnel Show Pty. Ltd. | Representative of AFSL licensee 448066
</div>
</div>
</div>
</div>
</section>
</div>
</div>
</div>
<div id="fp-nav" class="right"></div>
<div id="cli_dialog_div"></div>
</body>
</html>

@ -24,8 +24,14 @@
<a ui-sref="analysis_monitoring.risk_manager"><i class="fa fa-tv"></i> <span>风控记录|Risk Records</span></a>
</li>
<li ui-sref-active-eq="active" ng-if="('riskBusiness'|withModule)&&(currentUser.org_id==null)&&(currentUser.display_name == 'lujian' || currentUser.display_name == 'zhh')">
<a ui-sref="analysis_monitoring.risk_business"><i class="fa fa-tv"></i> <span>风控业务</span></a>
<!-- 风控 -->
<li ui-sref-active-eq="active" ng-if="('riskBusiness'|withModule) && ('10' | withRole)">
<a ui-sref="analysis_monitoring.risk_business"><i class="fa fa-tv"></i> <span>风控业务|Risk Business</span></a>
</li>
<!-- BD -->
<li ui-sref-active-eq="active" ng-if="('riskBusiness'|withModule) && ('100' | withRole)">
<a ui-sref="analysis_monitoring.risk_business_bd"><i class="fa fa-tv"></i> <span>风控业务|Risk Business</span></a>
</li>
</ul>

@ -4,29 +4,599 @@
define(['angular', 'jquery', 'uiRouter', './monitoring/analysis-monitoring'],
function (angular, $) {
'use strict';
var orderTypesMap = {
"1": "微信调单",
"2": "支付宝调单",
"3": "RoyalPay调单",
"4": "警告",
"5": "通用号调单"
};
var orderTypesMapForBD = {
"1": "微信调单",
"2": "支付宝调单"
};
var royalpayOrderTypesMap = {
"0": "正常调单",
"1": "单纯大金额频繁刷单"
};
var warningOrderTypesMap = {
"0": "单人多次大金额交易",
"1": "退款频繁"
};
var resultTypesMap = {
"0": "未处理",
"1": "已发送邮件",
"2": "已提交材料,等待审核",
"3": "材料审核通过",
"4": "材料审核不通过,已打回",
"5": "已处理"
};
var resultTypeSearchMap = {
"0": "未处理",
"1": "资料完善中",
"2": "等待风控",
"3": "材料通过",
"4": "材料打回",
"5": "已处理"
};
var resultTypeSearchMapForBD = {
"1": "材料待上传",
"2": "材料已提交",
"3": "材料通过",
"4": "材料打回",
"5": "已处理"
};
var emailStatusMap = {
"0": "未发送",
"1": "已发送",
"2": "打回并已发送",
"3": "已发送催促邮件"
};
var amountSectionMap = {
"0-500": "0-500",
"500-1000": "500-1000",
"1000-1500": "1000-1500",
"1500-2000": "1500-2000",
"2000-2500": "2000-2500",
"2500-3000": "2500-3000",
"3000-3500": "3000-3500",
"3500-4000": "3500-4000",
"4000-4500": "4000-4500"
};
var app = angular.module('riskBusinessApp', ['ui.router']);
app.config(['$stateProvider', function ($stateProvider) {
$stateProvider.state('analysis_monitoring.risk_business', {
url: '/risk_business',
templateUrl: '/static/analysis/templates/risk_business.html',
cache: false,
controller: 'riskBusinessCtrl'
}).state('analysis_monitoring.risk_business_bd', {
url: '/risk_business_bd',
templateUrl: '/static/analysis/templates/risk_business_bd.html',
cache: false,
controller: 'riskBusinessCtrl'
}).state('analysis_monitoring.risk_business.detail', {
}).state('analysis_monitoring.riskEvent_detail', {
url: '/{risk_id}/detail',
templateUrl: '/static/analysis/templates/riskEvent_detail.html',
controller: 'riskEventDetailCtrl',
resolve: {
partner: ['$http', '$stateParams', function ($http, $stateParams) {
return $http.get('/risk/business/event' + $stateParams.risk_id);
riskEvent: ['$http', '$stateParams', function ($http, $stateParams) {
return $http.get('/risk/business/events/' + $stateParams.risk_id);
}]
}
})
}).state('analysis_monitoring.riskEvent_detail_bd', {
url: '/{risk_id}/bd/detail',
templateUrl: '/static/analysis/templates/riskEvent_detail_bd.html',
controller: 'riskEventDetailCtrl',
resolve: {
riskEvent: ['$http', '$stateParams', function ($http, $stateParams) {
return $http.get('/risk/business/events/' + $stateParams.risk_id);
}]
}
}).state('analysis_monitoring.risk_business.new_riskEvent', {
url: '/new_riskEvent',
templateUrl: '/static/analysis/templates/new_riskEvent.html',
controller: 'newRiskEventCtrl'
}).state('analysis_monitoring.riskEvent_detail.audit_material', {
url: '/audit_material',
templateUrl: '/static/analysis/templates/audit_material.html',
controller: 'auditMaterialCtrl'
});
}]);
app.controller('riskBusinessCtrl', ['$scope', '$http','$filter','chartParser', function ($scope, $http,$filter,chartParser) {
app.controller('riskBusinessCtrl', ['$scope', '$state', '$http', '$uibModal', '$filter', 'commonDialog', 'industryMap',
function ($scope, $state, $http, $uibModal, $filter, commonDialog, industryMap) {
$scope.orderTypes = orderTypesMap;
$scope.orderTypesForBD = orderTypesMapForBD;
$scope.resultTypes = resultTypesMap;
$scope.resultSearchTypes = resultTypeSearchMap;
$scope.resultTypesForBD = resultTypeSearchMapForBD;
$scope.industries = industryMap.configs();
$scope.amountSection = amountSectionMap;
$scope.pagination = {};
$scope.params = {};
}]);
// 加载风险注册事件
$scope.loadRiskEvents = function (page) {
var params = angular.copy($scope.params);
params.page = page || $scope.pagination.page || 1;
params.replyEmailDate = $filter('date')(params.replyEmailDate, 'yyyy-MM-dd');
params.receiveEmailDate = $filter('date')(params.receiveEmailDate, 'yyyy-MM-dd');
if (params.section != null) {
var sectionArray = params.section.split('-');
params.startAmount = sectionArray[0];
params.endAmount = sectionArray[1];
}
$http.get('/risk/business/events', {params: params}).then(function (resp) {
$scope.riskEvents = resp.data.data;
$scope.pagination = resp.data.pagination;
});
};
$scope.loadRiskEvents(1);
}
]);
app.controller('riskEventDetailCtrl', ['$scope', '$state', '$http', '$uibModal', '$filter', 'Upload', 'commonDialog', 'riskEvent',
function ($scope, $state, $http, $uibModal, $filter, Upload, commonDialog, riskEvent) {
$scope.orderTypes = orderTypesMap;
$scope.resultTypes = resultTypesMap;
$scope.riskEvent = riskEvent.data;
// 获取数据库中对应的渠道字段
var orderChannel = 'enable_';
if ($scope.riskEvent.order_type == 1) {
orderChannel += 'wechat';
} else if ($scope.riskEvent.order_type == 2) {
orderChannel += 'alipay';
} else {
orderChannel = null;
}
// 编辑表格的数据保存对象,重新从源数据复制,从而取消保存操作时不会更新视图
$scope.riskEventEdit = angular.copy(riskEvent.data);
// order_type转换为string类型是因为前端select控件这样才会显示初值
$scope.riskEventEdit.order_type += "";
// 调单信息
$scope.tradeLogs = $scope.riskEvent.tradeLogs;
// 商户信息
$scope.clientInfo = $scope.riskEvent.clientInfo;
if (orderChannel != null)
$scope.enableChannel = $scope.clientInfo[orderChannel];
// 控制编辑表格的显示
$scope.editFlag = false;
$scope.changeEditFlag = function(editFlag) {
$scope.editFlag = !editFlag;
// 如果是在编辑状态需要将日期转换为date类型前端控件需要
// 如果是在非编辑状态需要将日期转换为yyyy-MM-dd格式
if ($scope.editFlag) {
$scope.riskEventEdit.receive_email_date = new Date($scope.riskEventEdit.receive_email_date.replace(/-/g, "/"));
$scope.riskEventEdit.reply_email_date = new Date($scope.riskEventEdit.reply_email_date.replace(/-/g, "/"));
} else {
$scope.riskEvent.receive_email_date = $filter('date')($scope.riskEvent.receive_email_date, 'yyyy-MM-dd');
$scope.riskEvent.reply_email_date = $filter('date')($scope.riskEvent.reply_email_date, 'yyyy-MM-dd');
}
};
$scope.save = function(form) {
if (form.$invalid) {
angular.forEach(form, function (item, key) {
if (key.indexOf('$') < 0) {
item.$dirty = true;
}
});
return;
}
// 保存时需要重新将日期转换为yyyy-MM-dd格式传入后端
$scope.riskEventEdit.reply_email_date = $filter('date')($scope.riskEventEdit.reply_email_date, 'yyyy-MM-dd');
$scope.riskEventEdit.receive_email_date = $filter('date')($scope.riskEventEdit.receive_email_date, 'yyyy-MM-dd');
$http.put('/risk/business/events', $scope.riskEventEdit).then(function (resp) {
commonDialog.alert({
title: 'Success',
content: 'Update riskEvent successfully',
type: 'success'
});
$state.reload('analysis_monitoring.riskEvent_detail');
}, function (resp) {
commonDialog.alert({
title: 'Error',
content: resp.data.message,
type: 'error'
});
});
};
/**
* 关停渠道
* @param orderType 调单类型
* @param channelFlag
* @param temporaryFlag 是否临时关停
*/
$scope.updateChannel = function (orderType, channelFlag, temporaryFlag) {
var channel;
if (orderType == "1")
channel = 'wechat';
else if (orderType == "2")
channel = 'alipay';
$scope.riskEvent.temporary_close_channel = temporaryFlag;
commonDialog.confirm({
title: 'Warning',
content: 'Are you sure?'
}).then(function () {
$http.put('/risk/business/channel/' + channel + '/permission/' + channelFlag, $scope.riskEvent).then(function () {
$state.reload('analysis_monitoring.riskEvent_detail');
}, function (resp) {
commonDialog.alert({
title: 'Failed to change ' + channel + ' channel permission status',
content: resp.data.message,
type: 'error'
})
});
})
};
// 关停商户
$scope.updateClient = function(isValid, temporaryFlag) {
$scope.riskEvent.temporary_close_merchant = temporaryFlag;
commonDialog.confirm({
title: 'Warning',
content: 'Are you sure?'
}).then(function () {
$http.put('/risk/business/partner/' + isValid, $scope.riskEvent).then(function () {
$state.reload('analysis_monitoring.riskEvent_detail');
}, function (resp) {
commonDialog.alert({title: 'Error', content: resp.data.message, type: 'error'});
})
})
};
$scope.resendUploadEmail = function () {
commonDialog.confirm({
title: 'Warning',
content: 'Please confirm sending mail.'
}).then(function () {
var url = '/risk/business/' + $scope.riskEvent.risk_id + '/upload_mail';
if ($scope.riskEvent.result_type == 1)
url = '/risk/business/' + $scope.riskEvent.risk_id + '/urge';
$http.put(url).then(function () {
$state.reload();
}, function (resp) {
commonDialog.alert({title: 'Error', content: resp.data.message, type: 'error'});
})
})
};
// 以下为BD上传材料相关
$scope.material={};
$scope.material.update_time=$filter('date')(new Date(), 'yyyy-MM-dd HH:mm:ss');
$scope.material.risk_id = $scope.riskEvent.risk_id;
$scope.uploadFile1 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file1Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file1Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file1Progress.value = value/(files.length*2);
})
}
$scope.material.file1_url = urls;
}
};
$scope.uploadFile2 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file2Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file2Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file2Progress.value = value/(files.length*2);
})
}
$scope.material.file2_url = urls;
}
};
$scope.uploadFile3 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file3Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file3Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file3Progress.value = value/(files.length*2);
})
}
$scope.material.file3_url = urls;
}
};
$scope.uploadFile4 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file4Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file4Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file4Progress.value = value/(files.length*2);
})
}
$scope.material.file4_url = urls;
}
};
$scope.uploadFile5 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file5Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file5Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file5Progress.value = value/(files.length*2);
})
}
$scope.material.file5_url = urls;
}
};
$scope.uploadFile6 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file6Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file6Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file6Progress.value = value/(files.length*2);
})
}
$scope.material.file6_url = urls;
}
};
$scope.submit = function (form) {
var codeKey = $scope.riskEvent.submit_url.substring($scope.riskEvent.submit_url.lastIndexOf('/') + 1);
$http.post('/risk/upload/' + codeKey, $scope.material).then(function (resp) {
commonDialog.alert({
title: 'Success',
content: 'Submit successfully',
type: 'success'
});
$state.go('analysis_monitoring.risk_business_bd');
}, function (resp) {
commonDialog.alert({
title: 'Error',
content: resp.data.message,
type: 'error'
});
});
}
}
]);
app.controller('auditMaterialCtrl', ['$scope', '$state', '$http', '$uibModal', '$filter', '$sce', 'commonDialog',
function ($scope, $state, $http, $uibModal, $filter, $sce, commonDialog) {
// 一键下载功能
$scope.downloadAsZip = function () {
return '/risk/business/' + $scope.riskEvent.risk_id + '/download/materialsAsZIP';
};
// 加载提交材料
// $scope.fileObject = {};
$scope.loadRiskMaterial = function() {
$http.get('/risk/business/' + $scope.riskEvent.risk_id + '/material').then(function(resp) {
$scope.riskMaterial = resp.data;
$scope.file1 = resp.data.file1;
$scope.file2 = resp.data.file2;
$scope.file3 = resp.data.file3;
$scope.file4 = resp.data.file4;
$scope.file5 = resp.data.file5;
$scope.file6 = resp.data.file6;
// for (var i = 1; i <= 10; i++) {
// var key = "file" + i;
// if (riskMaterial[key + '_url'] != null)
// $scope.fileObject[key] = riskMaterial[key + '_url'];
// }
// $scope.fileLength = Object.keys($scope.fileObject).length;
})
};
$scope.loadRiskMaterial();
// 材料审核
$scope.auditMaterial = function(auditType) {
var url = '/risk/business/events';
var warningMessageHTML = '是否确定<span style="color: green; font-weight: bolder; font-size: 20px;">通过</span>该材料?';
if (auditType == 4) {
url = '/risk/business/' + $scope.riskEvent.risk_id + '/refuse';
warningMessageHTML = '是否确定<span style="color: red; font-weight: bolder; font-size: 20px;">拒绝</span>该材料?'
}
commonDialog.confirm({
title: 'Warning',
contentHtml: $sce.trustAsHtml(warningMessageHTML)
}).then(function () {
$scope.riskEvent.result_type = auditType;
$http.put(url, $scope.riskEvent).then(function (resp) {
$state.go('^', {}, {reload: true});
}, function (resp) {
commonDialog.alert({
title: 'Error',
content: resp.data.message,
type: 'error'
});
});
});
}
}
]);
app.controller('newRiskEventCtrl', ['$scope', '$state', '$http', '$uibModal', '$filter', 'commonDialog',
function ($scope, $state, $http, $uibModal, $filter, commonDialog) {
$scope.today = new Date();
$scope.orderTypes = orderTypesMap;
$scope.royapayOrderTypes = royalpayOrderTypesMap;
$scope.warningOrderTypes = warningOrderTypesMap;
$scope.save = function(form) {
if (form.$invalid) {
angular.forEach(form, function (item, key) {
if (key.indexOf('$') < 0) {
item.$dirty = true;
}
});
return;
}
if ($scope.riskEvent.receive_email_date == null)
$scope.riskEvent.receive_email_date = new Date();
// 默认设置邮件回复截止日期为收到邮件的七天后,如果是内部调单,设置三天后
var replyDeadline = angular.copy($scope.riskEvent.receive_email_date);
if ($scope.riskEvent.order_type > 2)
replyDeadline.setDate(replyDeadline.getDate() + 3);
else
replyDeadline.setDate(replyDeadline.getDate() + 7);
$scope.riskEvent.reply_email_date = $filter('date')(replyDeadline, 'yyyy-MM-dd');
$scope.riskEvent.receive_email_date = $filter('date')($scope.riskEvent.receive_email_date, 'yyyy-MM-dd');
$http.post('/risk/business/events', $scope.riskEvent).then(function (resp) {
commonDialog.alert({
title: 'Success',
content: 'Register new riskEvent successfully',
type: 'success'
});
$state.go('^',{}, {reload: true});
}, function (resp) {
commonDialog.alert({
title: 'Error',
content: resp.data.message,
type: 'error'
});
});
};
$scope.partnerParam = {};
$scope.loadParnters = function() {
$scope.partnerParam.sub_merchant_id = $scope.riskEvent.sub_merchant_id;
$http.get('/risk/business/partners', {params: $scope.partnerParam}).then(function (resp) {
$scope.partners = resp.data;
$scope.riskEvent.client_moniker = $scope.partners[0].client_moniker;
if ($scope.partners != null && $scope.partners.length > 1 && $scope.riskEvent.order_type != 5)
commonDialog.confirm({
title: 'Warning',
content: '该微信子商户号下有多个商户,是否将调单类型改为通用号调单?'
}).then(function () {
$scope.riskEvent.order_type = 5 + "";
});
});
}
}
]);
// 调单类型过滤器
app.filter('orderType', function() {
return function(type) {
return orderTypesMap[type];
}
});
app.filter('royalPayOrderType', function() {
return function(type) {
return royalpayOrderTypesMap[type];
}
});
app.filter('warningOrderType', function() {
return function(type) {
return warningOrderTypesMap[type];
}
});
// 处理结果过滤器
app.filter('resultType', function() {
return function(type, resultTypesMap) {
return resultTypesMap[type];
}
});
// 邮件发送状态过滤器
app.filter('emailStatus', function() {
return function(status) {
return emailStatusMap[status];
}
});
return app;
});

@ -0,0 +1,159 @@
<style>
@media (max-width: 544px) {
.logo-width {
width: 100%;
}
}
</style>
<div class="panel panel-default" ng-if="fileLength != 0">
<div class="panel-heading">Audit Files &nbsp;&nbsp;&nbsp;
<a class="btn-group btn btn-success"
ng-href="{{downloadAsZip()}}"
target="_blank">
<i class="fa fa-cloud-download">一键下载</i>
</a>
<a class="btn-group btn btn-success pull-right"
ng-if="riskEvent.result_type == 2"
ng-click="auditMaterial(3)">通过
</a>
<a class="btn-group btn btn-warning pull-right"
ng-if="riskEvent.result_type == 2"
ng-click="auditMaterial(4)" style="margin: 0 10px">打回
</a>
</div>
<div class="panel-body">
<div class="form-vertical">
<div class="form-group">
<label class="control-label col-sm-2">Description:</label>
<div class="col-sm-8">
<div class="form-control-static">
<p ng-bind="riskMaterial.description"></p>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">1、物流公司发货单据照片
要求:每笔交易对应的物流单必须提供,且单据必须清晰可见<br>
Photos of logistics companies goods-delivery documents
Requirement: The logistics order record corresponding to each transaction must be provided, and details of records should be clearly visible.
</p>
<p ng-if="riskEvent.order_type==3">1.请解释相应的消费场景/业务模式,例如网站商城,扫码支付, 消费者到店支付等;<br>
Please explain the relative payment scenario/business activities, for example, online store, QR code payment, payment at the store, etc;
</p>
</div>
<div class="col-sm-12">
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<a class="col-xs-3 logo-width" ng-repeat="url in file1" target="_blank" ng-href="{{url}}">
<img class="col-xs-12" ng-src="{{url}}">
</a>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">2、用户购买虚拟物品需要提供聊天记录、订单信息、发货凭证截图、虚拟物品最终消费场景例如何种游戏、软件、提供消费场景网址/下载链接
要求:每笔交易对应的截图必须清晰可见<br>
Users need to provide chat records, order information, screenshots of delivery documents, final consumption scenarios of virtual goods (such as games, software); provide consumer scene URL / download link.
Requirement: The screenshot corresponding to each transaction must be clearly visible.
</p>
<p ng-if="riskEvent.order_type==3">2.提供相应购物清单,订单小票(请提供与被查交易订单号相匹配的交易时间及金额的发票);<br>
Provide related shopping lists, invoices. (Please provide the invoices, amount of which matches that of the abnormal transaction);
</p>
</div>
<div class="col-sm-12">
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<a class="col-xs-3 logo-width" ng-repeat="url in file2" target="_blank" ng-href="{{url}}">
<img class="col-xs-12" ng-src="{{url}}">
</a>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">3、购物小票/发票存根照片
照片应清晰,必须显示商户名称、商户地址、购物时间、物品名称
购物金额等<br>
Photos of shopping receipts/ invoice stubs
Requirement: The photos should be clear and must show Merchant name, Business address, Transaction time, Product information, Quantity purchased, etc.
</p>
<p ng-if="riskEvent.order_type==3">3.提供相应的发货证明,报关单(若有消费者在国内购买,请提供物流单据或报关单);<br>
Relative proof of delivery, customs declaration (If the consumer purchased from China, please provide shipping receipt or customs declaration);
</p>
</div>
<div class="col-sm-12">
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<a class="col-xs-3 logo-width" ng-repeat="url in file3" target="_blank" ng-href="{{url}}">
<img class="col-xs-12" ng-src="{{url}}">
</a>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">4、显示商户门牌号码和店头名称的照片
要求:清晰可见,至少一张<br>
Photos of Merchant Street number & Merchant name
Requirement: At least one visible photo
</p>
<p ng-if="riskEvent.order_type==3">4.提供您的门店照片(门店照及店铺内的照片各一张, 一张可以看到商户名的门头照,一张可以看到相关商品或服务的店内照片);<br>
Photos of the store ( one of each front-store and in-store);
</p>
</div>
<div class="col-sm-12">
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<a class="col-xs-3 logo-width" ng-repeat="url in file4" target="_blank" ng-href="{{url}}">
<img class="col-xs-12" ng-src="{{url}}">
</a>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">5、显示商户营业场景所场内部情况如店内商品陈列、收银台等的照片
要求:照片清晰,且能清楚显示商户实际售卖物品或服务,至少三张<br>
Photos of internal environment of merchant business (such as in-store merchandise display, checkout counter, etc.)
Requirements: The photos (at least three) showing merchant activities including actual selling-goods or services obviously
</p>
<p ng-if="riskEvent.order_type==3">5.其他可以还原交易背景的资料,如和消费者的聊天记录等,来佐证被查单号交易的真实性;<br>
Other materials that can verify the payment scenario, for example, chatting history, to prove the truth of the transactions;
</p>
</div>
<div class="col-sm-12">
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<a class="col-xs-3 logo-width" ng-repeat="url in file5" target="_blank" ng-href="{{url}}">
<img class="col-xs-12" ng-src="{{url}}">
</a>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1||riskEvent.order_type==3">6、其他图片<br>
Other pictures
</p>
</div>
<div class="col-sm-12">
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<a class="col-xs-3 logo-width" ng-repeat="url in file6" target="_blank" ng-href="{{url}}">
<img class="col-xs-12" ng-src="{{url}}">
</a>
</div>
</div>
</div>
</div>
</div>
</div>

@ -0,0 +1,203 @@
<div class="register-box-body register-box-bg">
<p class="login-box-msg">Easy BusinessEasy Payment</p>
<p class="small text-info login-box-msg">{{clientInfo.short_name}}</p>
<form novalidate name="uploadForm">
<div class="panel-body">
<div class="form-horizontal">
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">
1、物流公司发货单据照片
要求:每笔交易对应的物流单必须提供,且单据必须清晰可见<br>
Photos of logistics companies goods-delivery documents
Requirement: The logistics order record corresponding to each transaction must be provided,
and details of records should be clearly visible.
</p>
<p ng-if="riskEvent.order_type==3">
1.请解释相应的消费场景/业务模式,例如网站商城,扫码支付, 消费者到店支付等;<br>
Please explain the relative payment scenario/business activities,
for example, online store, QR code payment, payment at the store, etc;
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile1($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file1Progress.value" type="success" animate="true" ng-if="file1Progress.value" max="100"
>{{file1Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file1_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">
2、用户购买虚拟物品需要提供聊天记录、订单信息、发货凭证截图、
虚拟物品最终消费场景(例如何种游戏、软件)、提供消费场景网址/下载链接
要求:每笔交易对应的截图必须清晰可见<br>
Users need to provide chat records, order information, screenshots of delivery documents,
final consumption scenarios of virtual goods (such as games, software);
provide consumer scene URL / download link.
Requirement: The screenshot corresponding to each transaction must be clearly visible.
</p>
<p ng-if="riskEvent.order_type==3">
2.提供相应购物清单,订单小票(请提供与被查交易订单号相匹配的交易时间及金额的发票);<br>
Provide related shopping lists, invoices.
(Please provide the invoices, amount of which matches that of the abnormal transaction);
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile2($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file2Progress.value" type="success" animate="true" ng-if="file2Progress.value" max="100"
>{{file2Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file2_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">
3、购物小票/发票存根照片
照片应清晰,必须显示商户名称、商户地址、购物时间、物品名称
购物金额等<br>
Photos of shopping receipts/ invoice stubs
Requirement: The photos should be clear and must show Merchant name,
Business address, Transaction time, Product information, Quantity purchased, etc.
</p>
<p ng-if="riskEvent.order_type==3">
3.提供相应的发货证明,报关单(若有消费者在国内购买,请提供物流单据或报关单);<br>
Relative proof of delivery, customs declaration
(If the consumer purchased from China, please provide shipping receipt or customs declaration);
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile3($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file3Progress.value" type="success" animate="true" ng-if="file3Progress.value" max="100"
>{{file3Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file3_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">
4、显示商户门牌号码和店头名称的照片
要求:清晰可见,至少一张<br>
Photos of Merchant Street number & Merchant name
Requirement: At least one visible photo
</p>
<p ng-if="riskEvent.order_type==3">
4.提供您的门店照片(门店照及店铺内的照片各一张, 一张可以看到商户名的门头照,一张可以看到相关商品或服务的店内照片);<br>
Photos of the store ( one of each front-store and in-store);
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile4($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file4Progress.value" type="success" animate="true" ng-if="file4Progress.value" max="100"
>{{file4Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file4_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">
5、显示商户营业场景所场内部情况如店内商品陈列、收银台等的照片
要求:照片清晰,且能清楚显示商户实际售卖物品或服务,至少三张<br>
Photos of internal environment of merchant business
(such as in-store merchandise display, checkout counter, etc.)
Requirements: The photos (at least three)
showing merchant activities including actual selling-goods or services obviously
</p>
<p ng-if="riskEvent.order_type==3">
5.其他可以还原交易背景的资料,如和消费者的聊天记录等,来佐证被查单号交易的真实性;<br>
Other materials that can verify the payment scenario, for example,
chatting history, to prove the truth of the transactions;
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile5($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file5Progress.value" type="success" animate="true" ng-if="file5Progress.value" max="100"
>{{file5Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file5_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p>6、其他图片<br>
Other pictures
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile6($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file6Progress.value" type="success" animate="true" ng-if="file6Progress.value" max="100"
>{{file6Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file6_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Description</label>
<div class="col-sm-10">
<textarea class="form-control" required
ng-model="material.description" placeholder="No more than 500"
name="description"
maxlength="500"></textarea>
</div>
</div>
</div>
</div>
</form>
<div style="text-align: center">
<a role="button" style="margin-bottom: 25px;" class="btn btn-success btn-sm ng-scope" ng-disabled="!(material.description)"
ng-click="submit(uploadForm)">Submit</a>
</div>
</div>

@ -0,0 +1,223 @@
<section class="content-header">
<h1>New RiskEvent</h1>
</section>
<div class="content">
<form novalidate name="riskEventForm">
<div class="row">
<div class="col-sm-12">
<div class="panel panel-default">
<div class="panel-heading">RiskEvent Basic Information</div>
<div class="panel-body">
<div class="form-horizontal">
<div class="form-group"
ng-class="{'has-error':riskEventForm.order_type.$invalid && riskEventForm.order_type.$dirty}">
<label class="control-label col-sm-2"
for="order-type-input">Order Type
</label>
<div class="col-sm-8">
<select class="form-control"
name="order_type"
ng-model="riskEvent.order_type"
id="order-type-input"
required
ng-options="key as value for (key, value) in orderTypes">
<option value="">Please Choose</option>
</select>
<div ng-messages="riskEventForm.order_type.$error"
ng-if="riskEventForm.order_type.$dirty">
<p class="small text-danger"
ng-message="required">required field
</p>
</div>
</div>
</div>
<div class="form-group"
ng-if="riskEvent.order_type == 3"
ng-class="{'has-error':riskEventForm.royalpay_order_type.$invalid && riskEventForm.royalpay_order_type.$dirty}">
<label class="control-label col-sm-2"
for="royalpay-order-type-input">Royalpay Order Type
</label>
<div class="col-sm-8">
<select class="form-control"
name="royalpay_order_type"
ng-model="riskEvent.royalpay_order_type"
id="royalpay-order-type-input"
required
ng-options="key as value for (key, value) in royapayOrderTypes">
<option value="">Please Choose</option>
</select>
<div ng-messages="riskEventForm.royalpay_order_type.$error"
ng-if="riskEventForm.royalpay_order_type.$dirty">
<p class="small text-danger"
ng-message="required">required field
</p>
</div>
</div>
</div>
<div class="form-group"
ng-if="riskEvent.order_type == 4"
ng-class="{'has-error':riskEventForm.warning_order_type.$invalid && riskEventForm.warning_order_type.$dirty}">
<label class="control-label col-sm-2"
for="warning-order-type-input">Warning Type
</label>
<div class="col-sm-8">
<select class="form-control"
name="warning_order_type"
ng-model="riskEvent.warning_order_type"
id="warning-order-type-input"
required
ng-options="key as value for (key, value) in warningOrderTypes">
<option value="">Please Choose</option>
</select>
<div ng-messages="riskEventForm.warning_order_type.$error"
ng-if="riskEventForm.warning_order_type.$dirty">
<p class="small text-danger"
ng-message="required">required field
</p>
</div>
</div>
</div>
<div class="form-group"
ng-if="riskEvent.order_type == 5 || riskEvent.order_type == 1"
ng-class="{'has-error':riskEventForm.sub_merchant_id.$invalid && riskEventForm.sub_merchant_id.$dirty}">
<label class="control-label col-sm-2"
for="sub-merchant-id-input">Sub Merchant ID</label>
<div class="col-sm-8">
<input class="form-control"
ng-model="riskEvent.sub_merchant_id"
type="text"
name="sub_merchant_id"
id="sub-merchant-id-input"
ng-blur="loadParnters()"
required>
<div ng-messages="riskEventForm.order_ids.$error"
ng-if="riskEventForm.sub_merchant_id.$dirty">
<p class="small text-danger"
ng-message="required">required field
</p>
</div>
</div>
</div>
<div class="form-group" ng-if="partners != null">
<label class="control-label col-sm-2"
for="order-type-input">Company Name
</label>
<div class="col-sm-8">
<select class="form-control"
name="company_name"
ng-model="riskEvent.client_moniker"
id="company-name-input"
ng-options="partner.client_moniker as partner.company_name for partner in partners">
<option value="Please Choose"></option>
</select>
<div ng-messages="riskEventForm.order_type.$error"
ng-if="riskEventForm.order_type.$dirty">
<p class="small text-danger"
ng-message="required">required field
</p>
</div>
</div>
</div>
<div class="form-group"
ng-if="riskEvent.order_type != 5"
ng-class="{'has-error':riskEventForm.client_moniker.$invalid && riskEventForm.client_moniker.$dirty}">
<label class="control-label col-sm-2"
for="short-id-input">Partner Code
</label>
<div class="col-sm-8">
<input class="form-control"
ng-model="riskEvent.client_moniker"
type="text"
name="client_moniker"
id="short-id-input"
required
maxlength="6"
ng-pattern="/^[a-zA-Z0-9]+$/">
<div ng-messages="riskEventForm.client_moniker.$error"
ng-if="riskEventForm.client_moniker.$dirty">
<p class="small text-danger"
ng-message="required">Required Field
</p>
<p class="small text-danger"
ng-message="maxlength">Less Than 6 Letters
</p>
<p class="small text-danger"
ng-message="pattern">
Only Uppercase Letters and Numbers are allowed
</p>
</div>
</div>
</div>
<div class="form-group"
ng-if="riskEvent.order_type != 4"
ng-class="{'has-error':riskEventForm.order_ids.$invalid && riskEventForm.order_ids.$dirty}">
<label class="control-label col-sm-2"
for="order-ids-input">Order IDs</label>
<div class="col-sm-8">
<input class="form-control"
ng-model="riskEvent.order_ids"
type="text"
name="order_ids"
id="order-ids-input"
placeholder="order id1,order id2,order id3..."
required>
<div ng-messages="riskEventForm.order_ids.$error"
ng-if="riskEventForm.order_ids.$dirty">
<p class="small text-danger"
ng-message="required">required field
</p>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2"
for="receive-date-input">
{{(riskEvent.order_type == 1 || riskEvent.order_type ==2) ? 'Receive Date' : 'Create Date'}}
</label>
<div class="col-xs-2">
<input class="form-control"
id="receive-date-input"
type="text"
ng-model="riskEvent.receive_email_date"
uib-datepicker-popup
size="10"
placeholder="{{(riskEvent.order_type == 1 || riskEvent.order_type ==2) ? 'Receive Date' : 'Create Date'}}"
datepicker-options="{maxDate:today}"
is-open="ReceiveDate.open"
ng-click="ReceiveDate.open=true">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2"
for="description-input">Description
</label>
<div class="col-sm-8">
<textarea class="form-control"
ng-model="riskEvent.description"
name="description"
id="description-input">
</textarea>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="btn-group margin-bottom margin-top">
<button class="btn btn-success"
type="button"
ng-click="save(riskEventForm)">Save
</button>
</div>
</form>
</div>

@ -1,10 +1,479 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
欢迎来到riskDetail页面
</body>
</html>
<div class="content">
<div class="row">
<div class="col-sm-12">
<div class="nav-tabs-custom">
<ul class="nav nav-tabs">
<li ui-sref-active-eq="active">
<a ui-sref="analysis_monitoring.riskEvent_detail" ui-sref-opts="{reload:true}">Risk Detail</a>
</li>
<li ui-sref-active="active">
<a ui-sref=".audit_material" ui-sref-opts="{reload:true}">Audit material</a>
</li>
</ul>
<div class="tab-content" ui-view>
<div class="row" ng-if="!editFlag">
<div class="col-sm-12">
<div class="nav-tabs-custom">
<div class="tab-content">
<div class="panel panel-default">
<div class="panel-heading">
RiskEvent Basic Information
<a role="button"
class="pull-right"
ng-click="changeEditFlag(editFlag)">
<i class="fa fa-edit"></i> Edit
</a>
</div>
<div class="panel-body">
<div class="form-horizontal">
<div class="form-group" ng-if="riskEvent.client_moniker != null">
<label class="control-label col-sm-2">Partner Code</label>
<div class="col-sm-10">
<p class="form-control-static"
ng-bind="riskEvent.client_moniker"></p>
</div>
</div>
<div class="form-group" ng-if="clientInfo.short_name != null">
<label class="control-label col-sm-2">Short Name</label>
<div class="col-sm-10">
<p class="form-control-static"
ng-bind="clientInfo.short_name"></p>
</div>
</div>
<div class="form-group" ng-if="riskEvent.order_type == 1 || riskEvent.order_type == 5">
<label class="control-label col-sm-2">Sub Merchant ID</label>
<div class="col-sm-10">
<p class="form-control-static">
{{clientInfo.sub_merchant_id || riskEvent.sub_merchant_id}}
</p>
</div>
</div>
<div class="form-group" ng-if="riskEvent.order_ids != null">
<label class="control-label col-sm-2">Order IDs</label>
<div class="col-sm-10">
<p class="form-control-static"
ng-bind="riskEvent.order_ids">
</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Order Type</label>
<div class="col-sm-10">
<p class="form-control-static"
ng-bind="riskEvent.order_type | orderType">
</p>
</div>
</div>
<div class="form-group" ng-if="riskEvent.order_type == 3">
<label class="control-label col-sm-2">Royalpay Order Type</label>
<div class="col-sm-10">
<p class="form-control-static"
ng-bind="riskEvent.royalpay_order_type | royalPayOrderType">
</p>
</div>
</div>
<div class="form-group" ng-if="riskEvent.order_type == 4">
<label class="control-label col-sm-2">Waning Order Type</label>
<div class="col-sm-10">
<p class="form-control-static"
ng-bind="riskEvent.warning_order_type | warningOrderType">
</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Result Type</label>
<div class="col-sm-10">
<p class="form-control-static">
{{riskEvent.result_type | resultType:resultTypes}}
</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Email Status</label>
<div class="col-sm-10">
<p class="form-control-static"
ng-bind="riskEvent.email_status | emailStatus"></p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">
{{(riskEvent.order_type == 1 || riskEvent.order_type ==2) ? 'Receive Date' : 'Create Date'}}
</label>
<div class="col-sm-10">
<p class="form-control-static">
{{riskEvent.receive_email_date | limitTo:10}}
</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Reply Deadline</label>
<div class="col-sm-10">
<p class="form-control-static">
{{riskEvent.reply_email_date | limitTo:10}}
</p>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Description</label>
<div class="col-sm-10">
<p class="form-control-static"
ng-bind="riskEvent.description">
</p>
</div>
</div>
<div ng-if="clientInfo != null">
<div class="form-group" ng-if="riskEvent.result_type <= 2">
<label class="control-label col-sm-2">Operaction</label>
<div class="col-xs-2" ng-if="enableChannel == 1">
<button class="btn btn-info"
type="button"
ng-click="updateChannel(riskEvent.order_type, false, true)">临时关闭渠道
</button>
</div>
<div class="col-xs-2" ng-if="clientInfo.is_valid == 1">
<button class="btn btn-info"
type="button"
ng-click="updateClient(true, true)">临时关闭商户
</button>
</div>
</div>
<div ng-if="riskEvent.result_type > 2">
<div class="form-group">
<label class="control-label col-sm-2">加入商户黑名单</label>
<div class="col-xs-6">
<input type="checkbox"
bs-switch
ng-model="clientInfo.is_valid">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">加入用户黑名单</label>
<div class="col-xs-6">
<input type="checkbox"
ng-model="clientInfo.is_valid"
bs-switch>
</div>
</div>
</div>
<div class="form-group" ng-if="riskEvent.result_type > 2">
<label class="control-label col-sm-2">Handle Result</label>
<div class="col-xs-2" ng-if="riskEvent.temporary_close_channel != 1 && enableChannel == 1">
<button class="btn btn-info"
type="button"
ng-click="updateChannel(riskEvent.order_type, false, false)">关停渠道
</button>
</div>
<div class="col-xs-2" ng-if="riskEvent.temporary_close_merchant != 1 && clientInfo.is_valid == 1">
<button class="btn btn-info"
type="button"
ng-click="updateClient(true, false)">关停商户
</button>
</div>
<div class="col-xs-2">
<button class="btn btn-info"
ng-if="enableChannel == 0"
type="button"
ng-click="updateChannel(riskEvent.order_type, true, false)">重新启用渠道
</button>
</div>
<div class="col-xs-2" ng-if="clientInfo.is_valid == 0">
<button class="btn btn-info"
type="button"
ng-click="updateClient(false, false)">重新启用商户
</button>
</div>
</div>
<div class="form-group" ng-if="riskEvent.channel_result != null">
<label class="control-label col-sm-2">Channel Handle Result</label>
<div class="col-sm-10">
<p class="form-control-static">
{{riskEvent.channel_result}}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 调单信息 -->
<div class="box">
<div class="box-header">
<h3 class="box-title" style="display: inherit">
Orders Information
</h3>
</div>
<div class="box-body table-responsive">
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Order ID</th>
<th>Amount</th>
<th>Input Amount</th>
<th>AUD Amount</th>
<th>Exchange Rate</th>
<th>Status</th>
<th>Create Time</th>
<th>Gateway</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="trade in tradeLogs"
ng-class="{warning:trade.clearing_status==2}">
<td>{{trade.order_id}}</td>
<td>{{trade.total_amount | currency: trade.currency}}</td>
<td ng-bind="trade.display_amount | currency: trade.currency"></td>
<td ng-bind="trade.clearing_amount | currency: 'AUD'"></td>
<td>
<span ng-if="(trade.channel != 'hf') && (trade.channel != 'Rpay')"
ng-bind="trade.exchange_rate">
</span>
<span ng-if="(trade.channel == 'hf') || (trade.channel == 'Rpay')"> - </span>
</td>
<td ng-bind="trade.status"></td>
<td ng-bind="trade.create_time"></td>
<td ng-bind="trade.gateway"></td>
</tr>
</tbody>
</table>
</div>
</div>
<a role="button"
ng-if="riskEvent.result_type <= 1 && riskEvent.order_type < 4"
class="btn btn-info"
ng-click="resendUploadEmail()">Send Email {{riskEvent.result_type == 1 ? 'again' : ''}}
</a>
<a role="button"
ng-if="riskEvent.order_type == 4 && riskEvent.result_type == 0"
class="btn btn-info"
ng-click="resendUploadEmail()">Send Warning Email
</a>
<a role="button"
ui-sref="analysis_monitoring.risk_business"
class="btn btn-info pull-right">返回
</a>
</div>
</div>
</div>
</div>
<!--编辑表单-->
<form novalidate name="riskEventForm" ng-if="editFlag">
<div class="row">
<div class="col-sm-12">
<div class="panel panel-default">
<div class="panel-heading">RiskEvent Basic Information</div>
<div class="panel-body">
<div class="form-horizontal">
<div class="form-group"
ng-class="{'has-error':riskEventForm.order_type.$invalid && riskEventForm.order_type.$dirty}">
<label class="control-label col-sm-2"
for="order-type-input">Order Type
</label>
<div class="col-sm-8">
<select class="form-control"
name="order_type"
disabled
ng-model="riskEventEdit.order_type"
id="order-type-input"
required
ng-options="key as value for (key, value) in orderTypes">
<option value="">Please Choose</option>
</select>
<div ng-messages="riskEventForm.order_type.$error"
ng-if="riskEventForm.order_type.$dirty">
<p class="small text-danger"
ng-message="required">required field
</p>
</div>
</div>
</div>
<div class="form-group"
ng-if="riskEventEdit.order_type != 5"
ng-class="{'has-error':riskEventForm.client_moniker.$invalid && riskEventForm.client_moniker.$dirty}">
<label class="control-label col-sm-2"
for="short-id-input">* Partner Code
</label>
<div class="col-sm-8">
<input class="form-control text-uppercase"
ng-model="riskEventEdit.client_moniker"
type="text"
name="client_moniker"
id="short-id-input"
required
maxlength="6"
ng-pattern="/^[a-zA-Z0-9]+$/">
<div ng-messages="riskEventForm.client_moniker.$error"
ng-if="riskEventForm.client_moniker.$dirty">
<p class="small text-danger"
ng-message="required">Required Field
</p>
<p class="small text-danger"
ng-message="maxlength">Less Than 6 Letters
</p>
<p class="small text-danger"
ng-message="pattern">
Only Uppercase Letters and Numbers are allowed
</p>
</div>
</div>
</div>
<div class="form-group"
ng-if="riskEventEdit.order_type != 4"
ng-class="{'has-error':riskEventForm.order_ids.$invalid && riskEventForm.order_ids.$dirty}">
<label class="control-label col-sm-2"
for="order-ids-input">Order IDs
</label>
<div class="col-sm-8">
<input class="form-control"
ng-model="riskEventEdit.order_ids"
type="text"
name="order_ids"
id="order-ids-input"
required>
<div ng-messages="riskEventForm.order_ids.$error"
ng-if="riskEventForm.order_ids.$dirty">
<p class="small text-danger"
ng-message="required">required field
</p>
</div>
</div>
</div>
<div class="form-group"
ng-if="riskEventEdit.order_type == 5"
ng-class="{'has-error':riskEventForm.sub_merchant_id.$invalid && riskEventForm.sub_merchant_id.$dirty}">
<label class="control-label col-sm-2"
for="order-ids-input">Sub Merchant ID
</label>
<div class="col-sm-8">
<input class="form-control"
ng-model="riskEventEdit.sub_merchant_id"
type="text"
name="sub_merchant_id"
id="sub-merchant-id-input"
required>
<div ng-messages="riskEventForm.sub_merchant_id.$error"
ng-if="riskEventForm.sub_merchant_id.$dirty">
<p class="small text-danger"
ng-message="required">required field
</p>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2"
for="receive-email-input">
{{(riskEvent.order_type == 1 || riskEvent.order_type ==2) ? 'Receive Date' : 'Create Date'}}
</label>
<div class="col-sm-8">
<div style="display: inline-block">
<input class="form-control"
id="receive-email-input"
type="text"
ng-model="riskEventEdit.receive_email_date"
uib-datepicker-popup
size="10"
placeholder="{{(riskEvent.order_type == 1 || riskEvent.order_type ==2) ? 'Receive Date' : 'Create Date'}}"
is-open="receiveDate.open"
ng-click="receiveDate.open=true"
datepicker-options="{maxDate:today}">
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2"
for="reply-deadline-input">Reply Deadline
</label>
<div class="col-sm-8">
<div style="display: inline-block">
<input class="form-control"
id="reply-deadline-input"
type="text"
ng-model="riskEventEdit.reply_email_date"
uib-datepicker-popup
size="10"
placeholder="Reply Deadline"
is-open="replyDeadline.open"
ng-click="replyDeadline.open=true">
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2"
for="description-input">Description
</label>
<div class="col-sm-8">
<textarea class="form-control"
maxlength="5000"
ng-model="riskEventEdit.description"
name="description"
id="description-input">
</textarea>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2"
for="channel-result-input">Channel Handle Result
</label>
<div class="col-sm-8">
<input class="form-control"
ng-model="riskEventEdit.channel_result"
type="text"
name="description"
id="channel-result-input">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="btn-group margin-bottom margin-top">
<button class="btn btn-success"
style="margin-right: 10px;"
type="button"
ng-click="save(riskEventForm)">Save
</button>
<button class="btn btn-warning"
type="button"
ng-click="changeEditFlag(editFlag)">cancel
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>

@ -0,0 +1,256 @@
<div class="content">
<div class="row">
<div class="col-sm-12">
<!-- 调单信息 -->
<div class="box">
<div class="box-header">
<h3 class="box-title" style="display: inherit">
Orders Information
</h3>
</div>
<div class="box-body table-responsive">
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Order ID</th>
<th>Amount</th>
<th>Input Amount</th>
<th>AUD Amount</th>
<th>Exchange Rate</th>
<th>Status</th>
<th>Create Time</th>
<th>Gateway</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="trade in tradeLogs"
ng-class="{warning:trade.clearing_status==2}">
<td>{{trade.order_id}}</td>
<td>{{trade.total_amount | currency: trade.currency}}</td>
<td ng-bind="trade.display_amount | currency: trade.currency"></td>
<td ng-bind="trade.clearing_amount | currency: 'AUD'"></td>
<td>
<span ng-if="(trade.channel != 'hf') && (trade.channel != 'Rpay')"
ng-bind="trade.exchange_rate">
</span>
<span ng-if="(trade.channel == 'hf') || (trade.channel == 'Rpay')"> - </span>
</td>
<td ng-bind="trade.status"></td>
<td ng-bind="trade.create_time"></td>
<td ng-bind="trade.gateway"></td>
</tr>
</tbody>
</table>
</div>
</div>
<a role="button"
ui-sref="analysis_monitoring.risk_business_bd"
class="btn btn-info">返回
</a>
</div>
</div>
</div>
<div class="register-box-body register-box-bg box">
<p class="text-info login-box-msg">{{clientInfo.short_name}}</p>
<form novalidate name="uploadForm">
<div class="panel-body">
<div class="form-horizontal">
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">
1、物流公司发货单据照片
要求:每笔交易对应的物流单必须提供,且单据必须清晰可见<br>
Photos of logistics companies goods-delivery documents
Requirement: The logistics order record corresponding to each transaction must be provided,
and details of records should be clearly visible.
</p>
<p ng-if="riskEvent.order_type==3">
1.请解释相应的消费场景/业务模式,例如网站商城,扫码支付, 消费者到店支付等;<br>
Please explain the relative payment scenario/business activities,
for example, online store, QR code payment, payment at the store, etc;
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile1($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file1Progress.value" type="success" animate="true" ng-if="file1Progress.value" max="100"
>{{file1Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file1_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">
2、用户购买虚拟物品需要提供聊天记录、订单信息、发货凭证截图、
虚拟物品最终消费场景(例如何种游戏、软件)、提供消费场景网址/下载链接
要求:每笔交易对应的截图必须清晰可见<br>
Users need to provide chat records, order information, screenshots of delivery documents,
final consumption scenarios of virtual goods (such as games, software);
provide consumer scene URL / download link.
Requirement: The screenshot corresponding to each transaction must be clearly visible.
</p>
<p ng-if="riskEvent.order_type==3">
2.提供相应购物清单,订单小票(请提供与被查交易订单号相匹配的交易时间及金额的发票);<br>
Provide related shopping lists, invoices.
(Please provide the invoices, amount of which matches that of the abnormal transaction);
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile2($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file2Progress.value" type="success" animate="true" ng-if="file2Progress.value" max="100"
>{{file2Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file2_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">
3、购物小票/发票存根照片
照片应清晰,必须显示商户名称、商户地址、购物时间、物品名称
购物金额等<br>
Photos of shopping receipts/ invoice stubs
Requirement: The photos should be clear and must show Merchant name,
Business address, Transaction time, Product information, Quantity purchased, etc.
</p>
<p ng-if="riskEvent.order_type==3">
3.提供相应的发货证明,报关单(若有消费者在国内购买,请提供物流单据或报关单);<br>
Relative proof of delivery, customs declaration
(If the consumer purchased from China, please provide shipping receipt or customs declaration);
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile3($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file3Progress.value" type="success" animate="true" ng-if="file3Progress.value" max="100"
>{{file3Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file3_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">
4、显示商户门牌号码和店头名称的照片
要求:清晰可见,至少一张<br>
Photos of Merchant Street number & Merchant name
Requirement: At least one visible photo
</p>
<p ng-if="riskEvent.order_type==3">
4.提供您的门店照片(门店照及店铺内的照片各一张, 一张可以看到商户名的门头照,一张可以看到相关商品或服务的店内照片);<br>
Photos of the store ( one of each front-store and in-store);
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile4($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file4Progress.value" type="success" animate="true" ng-if="file4Progress.value" max="100"
>{{file4Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file4_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p ng-if="riskEvent.order_type==1">
5、显示商户营业场景所场内部情况如店内商品陈列、收银台等的照片
要求:照片清晰,且能清楚显示商户实际售卖物品或服务,至少三张<br>
Photos of internal environment of merchant business
(such as in-store merchandise display, checkout counter, etc.)
Requirements: The photos (at least three)
showing merchant activities including actual selling-goods or services obviously
</p>
<p ng-if="riskEvent.order_type==3">
5.其他可以还原交易背景的资料,如和消费者的聊天记录等,来佐证被查单号交易的真实性;<br>
Other materials that can verify the payment scenario, for example,
chatting history, to prove the truth of the transactions;
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile5($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file5Progress.value" type="success" animate="true" ng-if="file5Progress.value" max="100"
>{{file5Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file5_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-12 text-left">
<p>6、其他图片<br>
Other pictures
</p>
</div>
<div class="col-sm-12">
<div class="col-xs-12">
<button class="btn btn-primary" type="button"
ngf-select="uploadFile6($files)" ngf-multiple="true">
<i class="fa fa-upload"></i> Upload
</button>
</div>
&nbsp;&nbsp;<br>
<div class="col-xs-12">
<uib-progressbar value="file6Progress.value" type="success" animate="true" ng-if="file6Progress.value" max="100"
>{{file6Progress.value}}%</uib-progressbar>
<img class="col-xs-3 logo-width" ng-repeat="url in material.file6_url" ng-src="{{url}}">
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Description</label>
<div class="col-sm-10">
<textarea class="form-control" required
ng-model="material.description" placeholder="No more than 500"
name="description"
maxlength="500"></textarea>
</div>
</div>
</div>
</div>
</form>
<div style="text-align: center">
<a role="button" style="margin-bottom: 25px;" class="btn btn-success btn-sm ng-scope" ng-disabled="!(material.description)"
ng-click="submit(uploadForm)">Submit</a>
</div>
</div>

@ -1,23 +1,166 @@
<div class="content">
<div class="content" ui-view>
<div class="row">
<div class="col-sm-12">
<div class="box-solid">
<div class="box box-warning">
<div class="box-header">
<div class="form-inline">
<div class="form-group">
<label class="control-label" for="partner-code-search">Partner Code</label>
<input type="text" class="form-control" id="partner-code-search"
ng-model="params.client_moniker">
<div class="form-horizontal">
<!--Partner Code-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="partner-code-search">Partner Code
</label>
<div class="col-xs-6">
<input type="text"
class="form-control"
id="partner-code-search"
ng-model="params.clientMoniker">
</div>
</div>
<!--Sub Merchant ID-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="sub-merchant-id-search">Sub Merchant ID
</label>
<div class="col-xs-6">
<input type="text"
class="form-control"
id="sub-merchant-id-search"
placeholder="子商户号"
ng-model="params.subMerchantId">
</div>
</div>
<!--Order Type-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="order-type-input">Order Type
</label>
<div class="col-xs-6">
<select class="form-control"
name="order_type"
ng-model="params.orderType"
id="order-type-input"
ng-options="key as value for (key, value) in orderTypes">
<option value="">ALL</option>
</select>
</div>
</div>
<!--Order IDs-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="order-ids-input">Order IDs
</label>
<div class="col-xs-6">
<input class="form-control"
ng-model="params.orderIds"
type="text"
name="order_ids"
placeholder="多个订单请用逗号分隔"
id="order-ids-input">
</div>
</div>
<!--Result Type-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="order-type-input">Result Type
</label>
<div class="col-xs-6">
<select class="form-control"
name="result_type"
ng-model="params.resultType"
id="result-type-input"
ng-options="key as value for (key, value) in resultTypes">
<option value="">ALL</option>
</select>
</div>
</div>
<!--Industry-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="industry-select">Industry</label>
<div class="col-xs-6">
<select ng-model="params.industry"
id="industry-select"
class="form-control"
ng-options="industry.value as industry.label for industry in industries">
<option value="">All</option>
</select>
</div>
</div>
<!--Receive Email Date-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="receive-date-input">Receive Date
</label>
<div class="col-xs-6">
<input class="form-control"
id="receive-date-input"
type="text"
ng-model="params.receiveEmailDate"
uib-datepicker-popup
size="10"
placeholder="Receive Email Date"
datepicker-options="{maxDate:today}"
is-open="ReceiveDate.open"
ng-click="ReceiveDate.open=true">
</div>
</div>
<!--Reply Email Deadline-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="reply-deadline-input">Reply Deadline
</label>
<div class="col-xs-6">
<input class="form-control"
id="reply-deadline-input"
type="text"
ng-model="params.replyEmailDate"
uib-datepicker-popup
size="10"
placeholder="Reply Email Deadline"
is-open="ReplyDeadline.open"
ng-click="ReplyDeadline.open=true">
</div>
<div class="form-group">
<button class="btn btn-primary" type="button" ng-click="loadRiskEvents(1)"><i
class="fa fa-search"></i></button>
</div>
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="payment-select">Amount Section</label>
<div class="col-xs-6">
<select ng-model="params.section"
id="payment-select"
class="form-control"
ng-options="key as value for (key, value) in amountSection">
<option value="">All</option>
</select>
</div>
</div>
<div class="col-xs-12">
<button class="btn btn-primary"
type="button"
ng-click="loadRiskEvents(1)">
<i class="fa fa-search"></i>Search
</button>
<a role="button"
class="btn btn-info"
ui-sref=".new_riskEvent"
title="New Event">
<i class="fa fa-plus"></i>New Event
</a>
</div>
</div>
</div>
</div>
<div class="box">
<div class="box-header">
<h3 class="box-title">RiskEvent List</h3>
@ -27,61 +170,70 @@
<table class="table table-striped">
<thead>
<tr>
<th>Partner Code</th>
<th>order_type</th>
<th>Partner</th>
<th>Order Type</th>
<th>Result Type</th>
<th>Sub Merchant ID</th>
<th>Email Status</th>
<th>FillIn Person</th>
<th>Description</th>
<th>Channel Result</th>
<th>Risk Manager</th>
<th>Create Time</th>
<th>Operation</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="riskEvent in riskEvents">
<td ng-bind="riskEvent.client_moniker"></td>
<td ng-bind="riskEvent.order_type"></td>
<td ng-bind="riskEvent.sub_merchant_id"></td>
<td>
<span ng-if="riskEvent.email_status == 0">未发送</span>
<span ng-if="riskEvent.email_status == 1">已发送</span>
<a role="button" ui-sref="partners.detail({clientMoniker: riskEvent.client_moniker})">
{{riskEvent.short_name}}({{riskEvent.client_moniker}})
</a>
</td>
<td ng-bind="riskEvent.fillin_person"></td>
<td ng-bind="riskEvent.order_type | orderType"></td>
<td>
{{riskEvent.result_type | resultType:resultSearchTypes}}
</td>
<td ng-bind="riskEvent.sub_merchant_id"></td>
<td ng-bind="riskEvent.email_status | emailStatus"></td>
<td ng-bind="riskEvent.description | limitTo:20"></td>
<td ng-bind="riskEvent.channel_result"></td>
<td ng-bind="riskEvent.fillin_person"></td>
<td ng-bind="riskEvent.create_time"></td>
<td>
<a class="text-primary" role="button" title="Detail"
ui-sref="riskEvent.detail({client_apply_id:partner.client_apply_id})">
<a class="text-primary"
role="button"
title="Detail"
ui-sref="analysis_monitoring.riskEvent_detail({risk_id:riskEvent.risk_id})">
<i class="fa fa-search"></i> Detail
</a>
</td>
</tr>
</tbody>
</table>
</div>
<div class="box-footer" ng-if="partners.length">
<div class="box-footer"
ng-if="riskEvents.length">
<uib-pagination class="pagination"
total-items="pagination.totalCount"
boundary-links="true"
ng-model="pagination.page"
items-per-page="pagination.limit"
max-size="10"
ng-change="loadPartners()"
ng-change="loadRiskEvents()"
previous-text="&lsaquo;"
next-text="&rsaquo;"
first-text="&laquo;"
last-text="&raquo;"></uib-pagination>
last-text="&raquo;">
</uib-pagination>
<div class="row">
<div class="col-xs-12">Total Records:{{pagination.totalCount}};Total Pages:{{pagination.totalPages}}</div>
<div class="col-xs-12">
Total Records:{{pagination.totalCount}};Total Pages:{{pagination.totalPages}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>

@ -0,0 +1,181 @@
<div class="content" ui-view>
<div class="row">
<div class="col-sm-12">
<div class="box-solid">
<div class="box box-warning">
<div class="box-header">
<div class="form-horizontal">
<!--Partner Code-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="partner-code-search">Partner Code
</label>
<div class="col-xs-6">
<input type="text"
class="form-control"
id="partner-code-search"
ng-model="params.clientMoniker">
</div>
</div>
<!--Sub Merchant ID-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="sub-merchant-id-search">Sub Merchant ID
</label>
<div class="col-xs-6">
<input type="text"
class="form-control"
id="sub-merchant-id-search"
placeholder="子商户号"
ng-model="params.subMerchantId">
</div>
</div>
<!--Order Type-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="order-type-input">Order Type
</label>
<div class="col-xs-6">
<select class="form-control"
name="order_type"
ng-model="params.orderType"
id="order-type-input"
ng-options="key as value for (key, value) in orderTypesForBD">
<option value="">ALL</option>
</select>
</div>
</div>
<!--Order IDs-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="order-ids-input">Order IDs
</label>
<div class="col-xs-6">
<input class="form-control"
ng-model="params.orderIds"
type="text"
name="order_ids"
placeholder="多个订单请用逗号分隔"
id="order-ids-input">
</div>
</div>
<!--Result Type-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="order-type-input">Result Type
</label>
<div class="col-xs-6">
<select class="form-control"
name="result_type"
ng-model="params.resultType"
id="result-type-input"
ng-options="key as value for (key, value) in resultTypesForBD">
<option value="">ALL</option>
</select>
</div>
</div>
<!--Industry-->
<div class="form-group col-sm-6">
<label class="control-label col-xs-4 col-sm-4"
for="industry-select">Industry</label>
<div class="col-xs-6">
<select ng-model="params.industry"
id="industry-select"
class="form-control"
ng-options="industry.value as industry.label for industry in industries">
<option value="">ALL</option>
</select>
</div>
</div>
<div class="col-xs-12">
<button class="btn btn-primary"
type="button"
ng-click="loadRiskEvents(1)">
<i class="fa fa-search"></i>Search
</button>
</div>
</div>
</div>
</div>
<div class="box">
<div class="box-header">
<h3 class="box-title">RiskEvent List</h3>
</div>
<div class="box-body no-padding table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>Partner</th>
<th>Order Type</th>
<th>Result Type</th>
<th>Sub Merchant ID</th>
<th>Description</th>
<th>Channel Result</th>
<th>Risk Manager</th>
<th>Create Time</th>
<th>Operation</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="riskEvent in riskEvents">
<td>
<a role="button" ui-sref="partners.detail({clientMoniker: riskEvent.client_moniker})">
{{riskEvent.short_name}}({{riskEvent.client_moniker}})
</a>
</td>
<td ng-bind="riskEvent.order_type | orderType"></td>
<td ng-class="{'text-orange': (riskEvent.result_type == 1), 'text-green': (riskEvent.result_type == 3), 'text-red': (riskEvent.result_type == 4)}">
{{riskEvent.result_type | resultType:resultTypesForBD}}
</td>
<td ng-bind="riskEvent.sub_merchant_id"></td>
<td ng-bind="riskEvent.description | limitTo:20"></td>
<td ng-bind="riskEvent.channel_result"></td>
<td ng-bind="riskEvent.fillin_person"></td>
<td ng-bind="riskEvent.create_time"></td>
<td>
<a class="text-primary"
role="button"
title="Detail"
ui-sref="analysis_monitoring.riskEvent_detail_bd({risk_id:riskEvent.risk_id})">
<i class="fa fa-search"></i> Detail
</a>
</td>
</tr>
</tbody>
</table>
</div>
<div class="box-footer"
ng-if="riskEvents.length">
<uib-pagination class="pagination"
total-items="pagination.totalCount"
boundary-links="true"
ng-model="pagination.page"
items-per-page="pagination.limit"
max-size="10"
ng-change="loadRiskEvents()"
previous-text="&lsaquo;"
next-text="&rsaquo;"
first-text="&laquo;"
last-text="&raquo;">
</uib-pagination>
<div class="row">
<div class="col-xs-12">
Total Records:{{pagination.totalCount}};Total Pages:{{pagination.totalPages}}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

@ -0,0 +1,170 @@
// define(['angular', 'static/commons/commons', 'uiBootstrap', 'uiRouter', 'ngBootSwitch', 'ngFileUpload'], function (angular) {
// 'use strict';
var app = angular.module('riskUploadApp',['ngFileUpload','ui.bootstrap']);
app.controller('riskUploadCtrl', ['$scope','$http','Upload','$filter',function ($scope,$http,Upload,$filter) {
$scope.material={};
$scope.codeKey=document.getElementById('codeKey').value;
$scope.material.risk_id=document.getElementById('risk_id').value;
$scope.order_type=document.getElementById('order_type').value;
$scope.material.update_time=$filter('date')(new Date(), 'yyyy-MM-dd HH:mm:ss');
$scope.uploadFile1 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file1Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file1Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file1Progress.value = value/(files.length*2);
})
}
$scope.material.file1_url = urls;
}
};
$scope.uploadFile2 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file2Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file2Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file2Progress.value = value/(files.length*2);
})
}
$scope.material.file2_url = urls;
}
};
$scope.uploadFile3 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file3Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file3Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file3Progress.value = value/(files.length*2);
})
}
$scope.material.file3_url = urls;
}
};
$scope.uploadFile4 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file4Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file4Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file4Progress.value = value/(files.length*2);
})
}
$scope.material.file4_url = urls;
}
};
$scope.uploadFile5 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file5Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file5Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file5Progress.value = value/(files.length*2);
})
}
$scope.material.file5_url = urls;
}
};
$scope.uploadFile6 = function (files) {
if (files && files.length) {
var urls = new Array();
var value = 0;
$scope.file6Progress = {value: 0};
for (var i = 0; i < files.length; i++) {
var file = files[i];
Upload.upload({
url: '/attachment/riskFiles',
data: {file: file}
}).then(function (resp) {
urls.push(resp.data.url);
}, function (resp) {
delete $scope.file6Progress;
alert('Upload Failed');
}, function (evt) {
value += parseInt(100 * evt.loaded / evt.total );
$scope.file6Progress.value = value/(files.length*2);
})
}
$scope.material.file6_url = urls;
}
};
$scope.submit = function (form) {
$http.post('/risk/upload/'+$scope.codeKey, $scope.material).then(function (resp) {
// commonDialog.alert({title: 'Success', content: 'Submit successfully', type: 'success'});
alert('Submit successfully');
window.location.href="/risk_upload_success.html";
}, function (resp) {
alert('Submit failed');
// commonDialog.alert({title: 'Error', content: resp.data.message, type: 'error'});
});
}
}]);
// return app;
//
// })
Loading…
Cancel
Save