Merge remote-tracking branch 'origin/master'

# Conflicts:
#	src/main/java/au/com/royalpay/payment/manage/merchants/core/impls/ClientManagerImpl.java
master
yixian 7 years ago
commit cdb23f746b

@ -17,6 +17,7 @@ import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@ -174,7 +175,7 @@ public class PlatformClearAnalysisServiceImpl implements PlatformClearService {
params.put("settlement_fee", settleFee.getBigDecimal("settlement_fee"));
params.put("channel", channel);
params.put("last_update_date", new Date());
JSONObject sysClearData = getSystemClearingAmount(dateStr, null, channel);
JSONObject sysClearData = getSystemClearingAmount(dateStr, aliSettleLog, channel);
if (sysClearData != null && sysClearData.size() > 0) {
params.put("sys_pay_fee", sysClearData.getBigDecimal("sys_pay_fee"));
params.put("sys_refund_fee", sysClearData.getBigDecimal("sys_refund_fee"));
@ -292,22 +293,26 @@ public class PlatformClearAnalysisServiceImpl implements PlatformClearService {
return alipaySettleLog;
}
public JSONObject getSystemClearingAmount(Date settle_date, SettlementLog settlementLog, String channel) throws Exception {
public JSONObject getSystemClearingAmount(Date settle_date, Object settlementLog, String channel) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 02:00:00");
JSONObject sysLogs = new JSONObject();
String start_date = null;
String end_date = null;
if (StringUtils.equals("Alipay", channel)) {
JSONObject lastClearDay = estimateAnalysisMapper.findLastCleanDays(sdfClear.format(settle_date), 1);
start_date = sdf.format(lastClearDay.getDate("date_str"));
end_date = sdf.format(settle_date);
logger.info("Alipay System Settle Logs:" + start_date + "<====>" + end_date);
} else if (StringUtils.equals("Wechat", channel)) {
start_date = sdf.format(settlementLog.getStart());
end_date = sdf.format(settlementLog.getEnd());
SettlementLog wechatSettleLog = (SettlementLog) settlementLog;
start_date = sdf.format(wechatSettleLog.getStart());
end_date = sdf.format(wechatSettleLog.getEnd());
logger.info("Wechat System Settle Logs:" + start_date + "<====>" + end_date);
} else if (StringUtils.equals("AlipayOnline", channel)) {
JSONObject alipayOnlineSettleLog = (JSONObject) settlementLog;
logger.info("AlipayOnline System Settle Logs:" + alipayOnlineSettleLog.getDate("min_time") + "<====>" + alipayOnlineSettleLog.getDate("max_time"));
start_date = sdf.format(alipayOnlineSettleLog.getDate("min_time"));
end_date = sdf.format(DateUtils.addDays(alipayOnlineSettleLog.getDate("max_time"), 1));
} else {
return null;
}

@ -407,7 +407,7 @@ public class RetailAppServiceImp implements RetailAppService {
params.put("client_id", client_id);
PageList<JSONObject> orders = orderMapper.listTransactionsForApp(params,
new PageBounds(query.getPage(), query.getLimit(), Order.formString("create_time.desc")));
new PageBounds(query.getPage(), query.getLimit(), Order.formString("transaction_time.desc")));
TimeZoneUtils.switchTimeZone(orders, query.getTimezone(), "create_time", "transaction_time", "confirm_time");
ArrayList<String> date_contains = new ArrayList<>();
for (JSONObject order : orders) {
@ -429,7 +429,7 @@ public class RetailAppServiceImp implements RetailAppService {
default:
break;
}
Calendar calendar = (Calendar) order.get("create_time");
Calendar calendar = (Calendar) order.get("transaction_time");
String trade_date = DateFormatUtils.format(calendar, "yyyy-MM-dd");
String trade_time = DateFormatUtils.format(calendar, "HH:mm:ss");
order.put("trade_date", trade_date);
@ -444,8 +444,10 @@ public class RetailAppServiceImp implements RetailAppService {
date_query.setClient_ids((String[]) params.get("client_ids"));
}
JSONObject date_params = date_query.toParams(query.getTimezone());
date_params.put("begin",date_params.getDate("from"));
date_params.put("end",date_params.getDate("to"));
date_params.put("client_id", device.getIntValue("client_id"));
JSONObject analysis = orderMapper.analysisOrders(date_params);
JSONObject analysis = transactionAnalysisMapper.getClientTransaction(date_params);
order.put("date_total", analysis);
date_contains.add(trade_date);
}

@ -14,7 +14,6 @@ public interface CustomerImpressionService {
JSONObject findOne(int client_id,String customer_id);
void generateTag(int client_id);
void generate(int client_id);
void generateInfo();

@ -1,11 +1,21 @@
package au.com.royalpay.payment.manage.apps.core.impls;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import au.com.royalpay.payment.manage.apps.bean.CustomerImpressionQuery;
import au.com.royalpay.payment.manage.apps.core.CustomerImpressionService;
import au.com.royalpay.payment.manage.mappers.client.ClientCustomersMapper;
import au.com.royalpay.payment.manage.mappers.payment.OrderMapper;
import au.com.royalpay.payment.manage.mappers.system.CustomerMapper;
import au.com.royalpay.payment.manage.mappers.system.CustomerRelationAlipayMapper;
import au.com.royalpay.payment.tools.exceptions.BadRequestException;
import au.com.royalpay.payment.tools.exceptions.NotFoundException;
import au.com.royalpay.payment.tools.lock.Locker;
import au.com.royalpay.payment.tools.utils.PageListUtils;
import javax.annotation.Resource;
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 com.maxmind.geoip.LookupService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
@ -18,23 +28,11 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
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 com.maxmind.geoip.LookupService;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import au.com.royalpay.payment.manage.apps.bean.CustomerImpressionQuery;
import au.com.royalpay.payment.manage.apps.core.CustomerImpressionService;
import au.com.royalpay.payment.manage.mappers.client.ClientCustomersMapper;
import au.com.royalpay.payment.manage.mappers.payment.OrderMapper;
import au.com.royalpay.payment.manage.mappers.system.CustomerMapper;
import au.com.royalpay.payment.manage.mappers.system.CustomerRelationAlipayMapper;
import au.com.royalpay.payment.tools.exceptions.BadRequestException;
import au.com.royalpay.payment.tools.exceptions.NotFoundException;
import au.com.royalpay.payment.tools.lock.Locker;
import au.com.royalpay.payment.tools.lock.LockerRedisImpl;
import au.com.royalpay.payment.tools.utils.PageListUtils;
import javax.annotation.Resource;
/**
* Created by wangning on 2017/12/28.
@ -104,68 +102,6 @@ public class CustomerImpressionServiceImpl implements CustomerImpressionService
return customer;
}
@Override
public void generate(int client_id) {
Date now = new Date();
DateTime dt = new DateTime(2018, 1, 20, 0, 0);
if (now.compareTo(dt.toDate()) > 0) {
return;
}
JSONObject params = new JSONObject();
params.put("client_id", client_id);
params.put("include_success_status", 3);
PageList<JSONObject> lastRecord = clientCustomersMapper.listCustomerInfo(params, new PageBounds(1, 1, Order.formString("update_time.desc")));
if (!CollectionUtils.isEmpty(lastRecord)) {
params.put("confirm_time", lastRecord.get(0).getDate("update_time"));
}
List<JSONObject> orders = orderMapper.listAnalysisClientCustomer(params);
for (JSONObject order : orders) {
if (StringUtils.isEmpty(order.getString("channel"))) {
continue;
}
String customer_id = order.getString("customer_id");
JSONObject userInfo = customerMapper.findCustomerByOpenId(customer_id);
if (userInfo == null) {
userInfo = customerRelationAlipayMapper.findCustomerByUserId(customer_id);
}
JSONObject clientCustomerInfo = clientCustomersMapper.getClientCustomerWithNull(client_id, customer_id);
if (clientCustomerInfo == null) {
locker.lock(CUSTOMER_IMPRESSION_PREFIX + customer_id, 30_000, 30_000);
try {
JSONObject client_customer = new JSONObject();
client_customer.put("client_id", order.getIntValue("client_id"));
client_customer.put("customer_id", order.getString("customer_id"));
client_customer.put("channel", order.getString("channel"));
client_customer.put("tag", "不活跃用户");
if (userInfo != null) {
client_customer.put("headimg", userInfo.getString("headimg"));
client_customer.put("nick_name", userInfo.getString("nickname"));
}
client_customer.put("payment_times", order.getIntValue("payment_times"));
client_customer.put("total_amount", order.getBigDecimal("total_amount"));
client_customer.put("update_time", now);
client_customer.put("last_payment_time", order.getDate("confirm_time"));
clientCustomersMapper.insert(client_customer);
} finally {
locker.unlock(customer_id);
}
} else {
clientCustomerInfo.put("payment_times", clientCustomerInfo.getIntValue("payment_times") + order.getIntValue("payment_times"));
clientCustomerInfo.put("payment_times", order.getIntValue("payment_times"));
clientCustomerInfo.put("client_id", order.getIntValue("client_id"));
clientCustomerInfo.put("customer_id", order.getString("customer_id"));
clientCustomerInfo.put("total_amount", order.getBigDecimal("total_amount"));
if (userInfo != null) {
clientCustomerInfo.put("headimg", userInfo.getString("headimg"));
clientCustomerInfo.put("nick_name", userInfo.getString("nickname"));
}
clientCustomerInfo.put("last_payment_time", order.getDate("confirm_time"));
clientCustomersMapper.updateAfterPaymentFinish(clientCustomerInfo);
}
}
}
@Override
@Transactional
public void generateTag(int client_id) {
@ -197,10 +133,6 @@ public class CustomerImpressionServiceImpl implements CustomerImpressionService
@Override
public void generateInfo() {
Date now = new Date();
DateTime dt = new DateTime(2018, 1, 19, 3, 0);
if (dt.toDate().compareTo(now) > 0) {
return;
}
BoundListOperations<String, String> ops = stringRedisTemplate.boundListOps("customer_impression");
String redisValue = ops.leftPop();

@ -7,6 +7,7 @@ import org.apache.ibatis.annotations.Param;
import com.alibaba.fastjson.JSONObject;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.PageList;
import com.sun.tracing.dtrace.ProviderAttributes;
import cn.yixblog.support.mybatis.autosql.annotations.AutoMapper;
import cn.yixblog.support.mybatis.autosql.annotations.AutoSql;
@ -33,7 +34,11 @@ public interface BillOrderMapper {
@AutoSql(type = SqlType.SELECT)
List<JSONObject> findByBillId(@Param("bill_id") String bill_id);
List<String> findOrderIdByStatus(@Param("order_status")String order_status);
PageList<JSONObject> query(@Param("bill_id") String bill_id, @Param("param") JSONObject jsonObject, PageBounds pageBounds);
JSONObject analysis(@Param("bill_id")String bill_id,@Param("param")JSONObject jsonObject);
int updateStatusByOrderId(@Param("order_id")String order_id, @Param("order_status")String order_status);
}

@ -349,9 +349,9 @@ public class ClientManagerImpl implements ClientManager, ManagerTodoNoticeProvid
if (bdConfig != null) {
params.put("bd_group", bdConfig.getString("bd_group"));
List<JSONObject> listGroupBds = financialBDConfigMapper.listGroupBds(bdConfig.getString("bd_group"));
List<Integer> bdUserId = listGroupBds.stream().map(groupBd -> groupBd.getIntValue("manager_id")).collect(Collectors.toList());
List<String> bdUserId = listGroupBds.stream().map(groupBd -> groupBd.getString("manager_id")).collect(Collectors.toList());
if (params.containsKey("bd_user")) {
if (!bdUserId.contains(params.getIntValue("bd_user"))) {
if (!bdUserId.contains(params.getString("bd_user"))) {
params.remove("bd_user");
}
}

@ -0,0 +1,42 @@
package au.com.royalpay.payment.manage.task;
import au.com.royalpay.payment.manage.mappers.bill.BillOrderMapper;
import au.com.royalpay.payment.manage.mappers.payment.OrderMapper;
import com.alibaba.fastjson.JSONObject;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import javax.annotation.Resource;
/**
* Created by wangning on 2018/1/2.
*/
@Component
@ConditionalOnProperty(value = "app.run-tasks", havingValue = "true")
public class BillOrderCheckTask {
@Resource
private BillOrderMapper billOrderMapper;
@Resource
private OrderMapper orderMapper;
@Scheduled(cron = "0 0/3 * * * ?")
public void checkGreenChannel() {
List<String> orderIds = billOrderMapper.findOrderIdByStatus("0");
if(CollectionUtils.isEmpty(orderIds)){
return;
}
orderIds.forEach((p) -> {
JSONObject order = orderMapper.find(p);
if(order.getIntValue("status")==3||order.getIntValue("status")==1){
billOrderMapper.updateStatusByOrderId(p,"2");
}
});
}
}

@ -1,21 +1,21 @@
package au.com.royalpay.payment.manage.task;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import au.com.royalpay.payment.manage.apps.core.CustomerImpressionService;
import au.com.royalpay.payment.manage.mappers.system.ClientMapper;
import javax.annotation.Resource;
import com.alibaba.fastjson.JSONObject;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import au.com.royalpay.payment.manage.apps.core.CustomerImpressionService;
import au.com.royalpay.payment.manage.mappers.system.ClientMapper;
import javax.annotation.Resource;
/**
* Created by yishuqian on 12/03/2017.
@ -51,27 +51,6 @@ public class CustomerImpressionTask {
}
}
@Scheduled(cron = "0 0 3 * * ?")
public void generate() {
List<JSONObject> clients = clientMapper.listValidClient();
List<List<JSONObject>> splitList = new ArrayList<>();
for (int i = 0; i < clients.size(); i+=200) {
if(i+200>clients.size()){
splitList.add(clients.subList(i,clients.size()));
}else {
splitList.add(clients.subList(i,i+200));
}
}
for (List<JSONObject> splitClients : splitList) {
Runnable task = () -> splitClients.forEach((p)->{
System.out.println("当前执行到"+p.getIntValue("client_id"));
customerImpressionService.generate(p.getIntValue("client_id"));
});
generatePool.execute(task);
}
}
@Scheduled(cron = "0/1 * * * * ?")
public void generateInfo() {
customerImpressionService.generateInfo();

@ -1,15 +1,16 @@
package au.com.royalpay.payment.manage.task;
import java.util.List;
import javax.annotation.Resource;
import au.com.royalpay.payment.manage.mappers.ofei.TopUpOrderMapper;
import au.com.royalpay.payment.manage.ofei.core.OfeiServer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import au.com.royalpay.payment.manage.mappers.ofei.TopUpOrderMapper;
import au.com.royalpay.payment.manage.ofei.core.OfeiServer;
import java.util.List;
import javax.annotation.Resource;
/**
* Created by wangning on 2018/1/2.
@ -24,6 +25,9 @@ public class OfeiOrderCheckTask {
@Scheduled(cron = "0 0/20 * * * ?")
public void checkGreenChannel(){
List<String> orderIds = topUpOrderMapper.findOrderIdByStatus("10");
if(CollectionUtils.isEmpty(orderIds)){
return;
}
for (String orderId : orderIds) {
ofeiServer.checkOrder(orderId);
}

@ -746,8 +746,8 @@
select
IFNULL(sum(if(l.transaction_type='credit',l.clearing_amount,0)),0) trade_amount,
ifnull(sum(if(l.refund_id>0,l.clearing_amount,0)),0) refund_amount,
sum(if(l.transaction_type='Credit',1,0)) trade_count,
sum(if(l.refund_id>0,1,0)) refund_orders
ifnull(sum(if(l.transaction_type='Credit',1,0)),0) trade_count,
ifnull(sum(if(l.refund_id>0,1,0)),0) refund_orders
FROM pmt_transactions l
where l.channel!='Settlement' and l.system_generate=0
<if test="client_ids!=null">

@ -30,4 +30,14 @@
and order_status = #{param.status}
</if>
</select>
<select id="findOrderIdByStatus" resultType="java.lang.String">
select order_id from pmt_bill_order
where order_status = #{order_status}
</select>
<update id="updateStatusByOrderId">
update pmt_bill_order
set order_status = #{order_status}
where order_id = #{order_id}
</update>
</mapper>

@ -455,6 +455,8 @@
o.notify_url,
t.transaction_time,
t.system_transaction_id,
t.total_surcharge,
t.tax_amount,
o.status,
o.order_description,
o.order_detail,
@ -667,9 +669,9 @@
<if test="client_ids==null and client_id !=null">
and o.client_id=#{client_id}
</if>
<if test="from!=null">and o.create_time &gt;= #{from}</if>
<if test="to!=null">and o.create_time &lt; #{to}</if>
<if test="date!=null">and date(o.create_time)=date(#{date})
<if test="from!=null">and t.transaction_time &gt;= #{from}</if>
<if test="to!=null">and t.transaction_time &lt; #{to}</if>
<if test="date!=null">and date(t.transaction_time)=date(#{date})
</if>
<if test="trade_type!=null">and o.gateway in
<foreach collection="trade_type" item="gateway" open="(" close=")" separator=",">#{gateway}</foreach>

@ -127,6 +127,7 @@
<th>Rate</th>
<th>Total Charge</th>
<th>Net Amount</th>
<th>Tax Amount</th>
<th>Settle Days</th>
<th>Transactions</th>
</tr>
@ -143,6 +144,7 @@
<td ng-bind="settleItem.rate"></td>
<td ng-bind="settleItem.total_charge|currency:''"></td>
<td ng-bind="settleItem.clearing_amount|currency:''"></td>
<td ng-bind="settleItem.tax_amount"></td>
<td ng-bind="'T+'+settleItem.clear_days"></td>
<td>
<a ui-sref=".transactions({detailId:settleItem.clear_detail_id})" title="View Transactions">

@ -86,6 +86,12 @@
<span class="col-xs-6" ng-bind="report.clearing_amount|currency:''"></span>
</div>
</div>
<div class="row">
<div class="col-xs-6 col-sm-3">
<span class="col-xs-6 text-bold">Tax Amount</span>
<span class="col-xs-6" ng-bind="report.tax_amount|currency:''"></span>
</div>
</div>
</div>
</div>
<div class="box box-warning" ng-if="ctrl.channel!=null">
@ -128,6 +134,12 @@
<span class="col-xs-6" ng-bind="report.channels[ctrl.channel].gross_amount-report.channels[ctrl.channel].total_charge|currency:''"></span>
</div>
</div>
<div class="row">
<div class="col-xs-6 col-sm-3">
<span class="col-xs-6 text-bold">Tax Amount</span>
<span class="col-xs-6" ng-bind="report.tax_amount|currency:''"></span>
</div>
</div>
</div>
</div>
<div class="box box-default">
@ -143,7 +155,9 @@
<th>Total Amount</th>
<th>Clearing Amount</th>
<th>Surcharge Rate</th>
<th>Surcharge Amount</th>
<th>Settle Amount</th>
<th>Tax Amount</th>
<th>Remark</th>
</tr>
</thead>
@ -158,7 +172,9 @@
<td ng-bind="tr.transaction_amount|currency:''"></td>
<td ng-bind="tr.clearing_amount|currency:''"></td>
<td ng-bind="tr.surcharge_rate|percentage:1"></td>
<td ng-bind="(tr.total_surcharge?tr.total_surcharge:0)|currency:''"></td>
<td ng-bind="tr.settle_amount|currency:''"></td>
<td ng-bind="tr.tax_amount|currency:''"></td>
<td ng-bind="tr.remark"></td>
</tr>
</tbody>
@ -177,7 +193,9 @@
<th>Total Amount</th>
<th>Clearing Amount</th>
<th>Surcharge Rate</th>
<th>Surcharge Amount</th>
<th>Settle Amount</th>
<th>Tax Amount</th>
<th>Remark</th>
</tr>
</thead>
@ -191,7 +209,9 @@
<td ng-bind="tr.transaction_amount|currency:''"></td>
<td ng-bind="tr.clearing_amount|currency:''"></td>
<td ng-bind="tr.surcharge_rate|percentage:1"></td>
<td ng-bind="(tr.total_surcharge?tr.total_surcharge:0)|currency:''"></td>
<td ng-bind="tr.settle_amount|currency:''"></td>
<td ng-bind="tr.tax_amount|currency:''"></td>
<td ng-bind="tr.remark"></td>
</tr>
</tbody>

@ -110,7 +110,7 @@
</div>
</div>
<div class="box box-default">
<div class="box-header">BD Leader Commission</div>
<div class="box-header">BD Manager Commission</div>
<div class="box-body table-responsive">
<table class="table table-bordered table-hover table-striped">
<thead>
@ -138,7 +138,7 @@
</div>
</div>
<!--<div class="box box-default">-->
<div class="box box-warning">
<!--<div class="box box-warning">
<div class="box-header">BD Manager Commission</div>
<div class="box-body">
<div class="row">
@ -150,7 +150,7 @@
</div>
</div>
</div>
</div>
</div>-->
<div class="box box-success">
<div class="box-header">Director Commission</div>
<div class="box-body">

@ -77,6 +77,10 @@
<span class="col-xs-6 text-bold">Net Amount</span>
<span class="col-xs-6" ng-bind="report.clearing_amount|currency:''"></span>
</div>
<div class="col-xs-6 col-sm-3">
<span class="col-xs-6 text-bold">Tax Amount</span>
<span class="col-xs-6" ng-bind="report.tax_amount|currency:''"></span>
</div>
</div>
</div>
</div>
@ -133,6 +137,8 @@
<th>Total Amount</th>
<th>Clearing Amount</th>
<th>Surcharge Rate</th>
<th>Surcharge Amount</th>
<th>Tax Amount</th>
<th ng-if="report.report[0].settle_amount!=null">Settle Amount</th>
<th>Remark</th>
</tr>
@ -148,6 +154,8 @@
<td ng-bind="tr.transaction_amount"></td>
<td ng-bind="tr.clearing_amount"></td>
<td ng-bind="tr.surcharge_rate?(tr.surcharge_rate|percentage:1):report.channels[tr.channel].rate+'%'"></td>
<td ng-bind="tr.total_surcharge?tr.total_surcharge:0"></td>
<td ng-bind="tr.tax_amount"></td>
<td ng-if="tr.settle_amount!=null" ng-bind="tr.settle_amount|currency:''"></td>
<td ng-bind="tr.remark"></td>
</tr>

Loading…
Cancel
Save