Przeglądaj źródła

入账管理导出

wanxl 1 rok temu
rodzic
commit
5d54d5f3ca

+ 2 - 0
src/main/java/com/sqx/modules/app/dao/UserMoneyDetailsDao.java

@@ -3,6 +3,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.sqx.modules.app.entity.UserMoneyDetails;
+import com.sqx.modules.exportExecl.dto.AccountEntry;
 import com.sqx.modules.pay.controller.query.CashOutQueryDTO;
 import com.sqx.modules.pay.controller.query.WalletDetailQuery;
 import com.sqx.modules.pay.vo.CashOutVO;
@@ -44,4 +45,5 @@ public interface UserMoneyDetailsDao extends BaseMapper<UserMoneyDetails> {
                                            @Param("userPhone") String userPhone, @Param("couponName") String couponName,
                                            @Param("orderNumber") String orderNumber, @Param("startTime") String startTime, @Param("endTime") String endTime);
 
+    List<UserMoneyDetails> excelAccountEntry(@Param("query") AccountEntry query);
 }

+ 8 - 0
src/main/java/com/sqx/modules/app/service/UserMoneyDetailsService.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
 import com.sqx.common.utils.PageUtils;
 import com.sqx.common.utils.Result;
 import com.sqx.modules.app.entity.UserMoneyDetails;
+import com.sqx.modules.exportExecl.dto.AccountEntry;
 import com.sqx.modules.pay.controller.query.CashOutQueryDTO;
 import com.sqx.modules.pay.controller.query.WalletDetailQuery;
 import com.sqx.modules.utils.excel.ExcelData;
@@ -54,4 +55,11 @@ public interface UserMoneyDetailsService extends IService<UserMoneyDetails> {
      */
     PageUtils accountEntryManagementDetails(Integer page, Integer limit, String shopName, String shopPhone, String userPhone, String couponName, String orderNumber, String startTime, String endTime);
 
+    /**
+     * 入账管理导出
+     * @param query
+     * @return
+     */
+    ExcelData excelAccountEntry(AccountEntry query);
+
 }

+ 45 - 0
src/main/java/com/sqx/modules/app/service/impl/UserMoneyDetailsServiceImpl.java

@@ -9,6 +9,7 @@ import com.sqx.common.utils.Result;
 import com.sqx.modules.app.dao.UserMoneyDetailsDao;
 import com.sqx.modules.app.entity.UserMoneyDetails;
 import com.sqx.modules.app.service.UserMoneyDetailsService;
+import com.sqx.modules.exportExecl.dto.AccountEntry;
 import com.sqx.modules.pay.controller.query.CashOutQueryDTO;
 import com.sqx.modules.pay.controller.query.WalletDetailQuery;
 import com.sqx.modules.pay.vo.CashOutVO;
@@ -148,4 +149,48 @@ public class UserMoneyDetailsServiceImpl extends ServiceImpl<UserMoneyDetailsDao
         System.out.println("list = " + list);
         return pageUtils;
     }
+
+    /**
+     * @param query
+     * @return
+     */
+    @Override
+    public ExcelData excelAccountEntry(AccountEntry query) {
+        List<UserMoneyDetails> userMoneyDetailsList = baseMapper.excelAccountEntry(query);
+        ExcelData data = new ExcelData();
+        data.setName("入账管理");
+        List<String> titleList=Arrays.asList(
+                "编号",
+                "店铺名称",
+                "店铺手机号",
+                "下单用户",
+                "用户手机号",
+                "标题",
+                "优惠活动标题",
+                "优惠活动金额",
+                "跑腿费",
+                "订单号",
+                "金额",
+                "创建时间");
+        data.setTitles(titleList);
+        List<List<Object>> rows = new ArrayList<>();
+        for (UserMoneyDetails userMoneyDetails:userMoneyDetailsList ){
+            List<Object> row = new ArrayList<>();
+            row.add(userMoneyDetails.getId());
+            row.add(userMoneyDetails.getShopName());
+            row.add(userMoneyDetails.getShopPhone());
+            row.add(userMoneyDetails.getUserName());
+            row.add(userMoneyDetails.getUserPhone());
+            row.add(userMoneyDetails.getTitle());
+            row.add(userMoneyDetails.getCouponName());
+            row.add(userMoneyDetails.getCouponMoney());
+            row.add(userMoneyDetails.getErrandMoney());
+            row.add(userMoneyDetails.getOrderNumber()+"");
+            row.add(userMoneyDetails.getMoney());
+            row.add(userMoneyDetails.getCreateTime());
+            rows.add(row);
+        }
+        data.setRows(rows);
+        return data;
+    }
 }

+ 48 - 57
src/main/java/com/sqx/modules/exportExecl/controller/ExportExeclController.java

@@ -9,6 +9,7 @@ import com.sqx.common.utils.Result;
 import com.sqx.common.utils.SftpUtil;
 import com.sqx.modules.common.service.CommonInfoService;
 import com.sqx.modules.datacentre.query.ShopCenterQuery;
+import com.sqx.modules.exportExecl.dto.AccountEntry;
 import com.sqx.modules.exportExecl.mapper.ExportJobMapper;
 import com.sqx.modules.exportExecl.model.ExportJob;
 import com.sqx.modules.exportExecl.service.ExportJobService;
@@ -45,8 +46,6 @@ public class ExportExeclController {
 
     private final AppOrderDao appOrderDao;
 
-    private final ExportJobMapper exportJobMapper;
-
     private final ExportJobService exportJobService;
 
     private final CommonInfoService commonInfoService;
@@ -95,8 +94,8 @@ public class ExportExeclController {
         exportJob.setUserId(userId);
         exportJob.setCreateTime(new Date());
         exportJob.setUpdateTime(new Date());
-        int a=exportJobMapper.insert(exportJob);
-        if (a==1){
+        boolean a=exportJobService.save(exportJob);
+        if (a){
             return Result.success("新增导出计划成功");
         }else{
             return Result.error("新增导出计划失败");
@@ -108,23 +107,13 @@ public class ExportExeclController {
         if(!StringUtils.hasText(userId)){
             return Result.error("用户id不能为空");
         }
-        StringBuffer stringBuffer=new StringBuffer();
+        StringBuilder stringBuffer=new StringBuilder();
         if(rechargeOrder!=null&&rechargeOrder!=""){stringBuffer.append("充值订单号:"+rechargeOrder+";");}
         if(acount!=null&&acount!=""){stringBuffer.append("被充值账号:"+acount+";");}
 
-        ExportJob exportJob =new ExportJob();
-        exportJob.setFlag(0);
-        exportJob.setFileType("recharge");
-        exportJob.setConditionDetail(stringBuffer.toString());
-        exportJob.setConditions(","+rechargeOrder+","+acount);
-        LocalDateTime localDateTime = LocalDateTime.now();
-        String time=localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
-        exportJob.setFileName(time+"充值记录.xlsx");
-        exportJob.setCreateTime(new Date());
-        exportJob.setUpdateTime(new Date());
-        exportJob.setUserId(userId);
-        int a=exportJobMapper.insert(exportJob);
-        if (a==1){
+        ExportJob exportJob =this.buildExportJob("充值记录.xlsx","recharge", userId,stringBuffer.toString(),","+rechargeOrder+","+acount);
+        boolean a=exportJobService.save(exportJob);
+        if (a){
             return Result.success("新增导出计划成功");
         }else{
             return Result.error("新增导出计划失败");
@@ -137,19 +126,9 @@ public class ExportExeclController {
         if(queryDTO.getUserId()==null){
             return Result.error("用户id不能为空");
         }
-        ExportJob exportJob =new ExportJob();
-        exportJob.setFlag(0);
-        exportJob.setFileType("payouts");
-        exportJob.setConditionDetail(queryDTO.toStrMessage());
-        exportJob.setConditions(queryDTO.toStrCode());
-        LocalDateTime localDateTime = LocalDateTime.now();
-        String time=localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
-        exportJob.setFileName(time+"提现管理.xlsx");
-        exportJob.setCreateTime(new Date());
-        exportJob.setUpdateTime(new Date());
-        exportJob.setUserId(queryDTO.getUserId()+"");
-        int a=exportJobMapper.insert(exportJob);
-        if (a==1){
+        ExportJob exportJob =this.buildExportJob("提现管理.xlsx","payouts", String.valueOf(queryDTO.getUserId()),queryDTO.toStrMessage(),queryDTO.toStrCode());
+        boolean a=exportJobService.save(exportJob);
+        if (a){
             return Result.success("新增提现管理导出计划成功");
         }else{
             return Result.error("新增提现管理导出计划失败");
@@ -162,19 +141,9 @@ public class ExportExeclController {
         if(!StringUtils.hasText(queryDTO.getUserId())){
             return Result.error("用户id不能为空");
         }
-        ExportJob exportJob =new ExportJob();
-        exportJob.setFlag(0);
-        exportJob.setFileType("deposit");
-        exportJob.setConditionDetail(queryDTO.toStrMessage());
-        exportJob.setConditions(queryDTO.toStrCode());
-        LocalDateTime localDateTime = LocalDateTime.now();
-        String time=localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
-        exportJob.setFileName(time+"保证金记录.xlsx");
-        exportJob.setCreateTime(new Date());
-        exportJob.setUpdateTime(new Date());
-        exportJob.setUserId(queryDTO.getUserId()+"");
-        int a=exportJobMapper.insert(exportJob);
-        if (a==1){
+        ExportJob exportJob =this.buildExportJob("保证金记录.xlsx","deposit",queryDTO.getUserId(),queryDTO.toStrMessage(),queryDTO.toStrCode());
+        boolean a=exportJobService.save(exportJob);
+        if (a){
             return Result.success("新增保证金记录导出计划成功");
         }else{
             return Result.error("新增保证金记录导出计划失败");
@@ -244,28 +213,50 @@ public class ExportExeclController {
         }
     }
 
+    //构建导出对象
+    private ExportJob buildExportJob(String fileName,String fileType,String userId,String condDetail,String condCode){
+        ExportJob exportJob=new ExportJob();
+        //设置为待导出
+        exportJob.setFlag(0);
+        exportJob.setFileType(fileType);
+        exportJob.setConditionDetail(condDetail);
+        exportJob.setConditions(condCode);
+        LocalDateTime localDateTime = LocalDateTime.now();
+        String time=localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
+        exportJob.setFileName(time+fileName);
+        exportJob.setCreateTime(new Date());
+        exportJob.setUpdateTime(new Date());
+        exportJob.setUserId(userId);
+        return exportJob;
+    }
+
     @GetMapping("excelShopCenter")
     @ApiOperation("导出商户收益统计")
     public Result excelShopCenter(ShopCenterQuery queryDTO) throws Exception{
         if(!StringUtils.hasText(queryDTO.getUserId())){
             return Result.error("用户id不能为空");
         }
-        ExportJob exportJob =new ExportJob();
-        exportJob.setFlag(0);
-        exportJob.setFileType("shopCenter");
-        exportJob.setConditionDetail(queryDTO.toStrMessage());
-        exportJob.setConditions(queryDTO.toStrCode());
-        LocalDateTime localDateTime = LocalDateTime.now();
-        String time=localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
-        exportJob.setFileName(time+"商铺收益排行.xlsx");
-        exportJob.setCreateTime(new Date());
-        exportJob.setUpdateTime(new Date());
-        exportJob.setUserId(queryDTO.getUserId()+"");
-        int a=exportJobMapper.insert(exportJob);
-        if (a==1){
+        ExportJob exportJob =this.buildExportJob("商铺收益排行.xlsx","shopCenter",queryDTO.getUserId(),queryDTO.toStrMessage(),queryDTO.toStrCode());
+        boolean a=exportJobService.save(exportJob);
+        if (a){
             return Result.success("新增商铺收益排行导出计划成功");
         }else{
             return Result.error("新增商铺收益排行导出计划失败");
         }
     }
+
+    @GetMapping("excelAccountEntry")
+    @ApiOperation("导出入账管理")
+    public Result excelAccountEntry(AccountEntry queryDTO) throws Exception{
+        if(!StringUtils.hasText(queryDTO.getUserId())){
+            return Result.error("用户id不能为空");
+        }
+        ExportJob exportJob =this.buildExportJob("入账管理.xlsx","accountEntry",queryDTO.getUserId(),queryDTO.toStrMessage(),queryDTO.toStrCode());
+        boolean a=exportJobService.save(exportJob);
+        if (a){
+            return Result.success("新增入账管理导出计划成功");
+        }else{
+            return Result.error("新增入账管理导出计划失败");
+        }
+    }
 }

+ 39 - 0
src/main/java/com/sqx/modules/exportExecl/dto/AccountEntry.java

@@ -0,0 +1,39 @@
+package com.sqx.modules.exportExecl.dto;
+
+import lombok.Data;
+import org.springframework.util.StringUtils;
+
+@Data
+public class AccountEntry {
+
+    private String shopName;
+    private String shopPhone;
+    private String userPhone;
+    private String couponName;
+    private String orderNumber;
+    private String startTime;
+    private String endTime;
+    private String userId;
+
+    public String toStrMessage() {
+        return (StringUtils.hasText(shopName) ? "商铺名称:" + shopName + ";" : "") +
+                (StringUtils.hasText(shopPhone) ? "商铺手机号:" + shopPhone + ";" : "") +
+                (StringUtils.hasText(userPhone) ? "用户手机号:" + userPhone + ";" : "") +
+                (StringUtils.hasText(couponName) ? "优惠活动:" + couponName + ";" : "") +
+                (StringUtils.hasText(orderNumber) ? "订单号:" + orderNumber + ";" : "") +
+                (StringUtils.hasText(startTime) ? "开始时间:" + startTime + ";" : "") +
+                (StringUtils.hasText(endTime) ? "结束时间:" + endTime + ";" : "");
+    }
+
+    public String toStrCode() {
+        return
+                ","+(shopName==null?"":shopName)
+                +","+(shopPhone==null?"":shopPhone)
+                +","+(userPhone==null?"":userPhone)
+                +","+(couponName==null?"":couponName)
+                +","+(orderNumber==null?"":orderNumber)
+                +","+(startTime==null?"":startTime)
+                +","+(endTime==null?"":endTime)
+                +",";
+    }
+}

+ 23 - 15
src/main/java/com/sqx/scheduler/export/ExportScheduler.java

@@ -1,7 +1,6 @@
 package com.sqx.scheduler.export;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.sqx.common.utils.SftpUtil;
 import com.sqx.modules.app.entity.RechargeRecord;
 import com.sqx.modules.app.service.RechargeRecordService;
@@ -9,7 +8,7 @@ import com.sqx.modules.app.service.UserMoneyDetailsService;
 import com.sqx.modules.common.service.CommonInfoService;
 import com.sqx.modules.datacentre.query.ShopCenterQuery;
 import com.sqx.modules.datacentre.service.DataCentreService;
-import com.sqx.modules.exportExecl.mapper.ExportJobMapper;
+import com.sqx.modules.exportExecl.dto.AccountEntry;
 import com.sqx.modules.exportExecl.model.ExportJob;
 import com.sqx.modules.exportExecl.service.ExportJobService;
 import com.sqx.modules.order.service.AppOrderService;
@@ -23,18 +22,15 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
-import java.io.File;
 import java.io.InputStream;
 import java.math.BigDecimal;
 import java.util.ArrayList;
@@ -118,6 +114,8 @@ public class ExportScheduler {
                         excelData=getDepositExcelData(exportJob);
                     }else if("shopCenter".equals(fileType)){
                         excelData=getShopCenterExcelData(exportJob);
+                    }else if("accountEntry".equals(fileType)){
+                        excelData=getAccountEntryExcelData(exportJob);
                     }else{
                         continue;
                     }
@@ -161,6 +159,7 @@ public class ExportScheduler {
             log.info("执行:通用数据导出定时任务"+exportJob.getExportId()+"......执行任务完成,执行时长:{} s", (edTime - bgTime) / 1000);
         }
     }
+
     //订单导出
     private ExcelData getOrderExcelData(ExportJob exportJob){
         String[] conditions=exportJob.getConditions().split(",",-1);
@@ -186,9 +185,8 @@ public class ExportScheduler {
         String endTime=conditions[10];
         String payStartTime=conditions[11];
         String payEndTime=conditions[12];
-        ExcelData excelData = appOrderService.excelAllOrderAdmin(status, phone, shopId, userName, orderNumber, orderType, shopName, riderPhone, startTime, endTime,payStartTime,payEndTime);
 
-        return excelData;
+        return appOrderService.excelAllOrderAdmin(status, phone, shopId, userName, orderNumber, orderType, shopName, riderPhone, startTime, endTime,payStartTime,payEndTime);
     }
 
     //充值记录导出
@@ -196,7 +194,7 @@ public class ExportScheduler {
         String[] conditions=exportJob.getConditions().split(",",-1);
         String rechargeOrder=conditions[1];
         String acount=conditions[2];
-        QueryWrapper qw=new QueryWrapper<RechargeRecord>();
+        QueryWrapper<RechargeRecord> qw=new QueryWrapper<RechargeRecord>();
         if(StringUtils.hasText(rechargeOrder)){
             qw.eq("order_no",rechargeOrder);
         }
@@ -205,16 +203,16 @@ public class ExportScheduler {
         }
         ExcelData data = new ExcelData();
         data.setName("订单列表");
-        List<String> titles = new ArrayList();
+        List<String> titles = new ArrayList<>();
         titles.add("用户id");titles.add("编号");titles.add("充值金额");titles.add("充值前余额");
         titles.add("充值后余额"); titles.add("被充值账号(手机号)");titles.add("被充值名称");titles.add("被充值昵称");
         titles.add("被充值头像"); titles.add("更新时间");titles.add("充值时间");titles.add("充值人账号");
         titles.add("备注");
         data.setTitles(titles);
         List<RechargeRecord> recordList=rechargeRecordService.list(qw);
-        List<List<Object>> rows = new ArrayList();
+        List<List<Object>> rows = new ArrayList<>();
         for (RechargeRecord record:recordList){
-            List<Object> row = new ArrayList();
+            List<Object> row = new ArrayList<>();
             row.add(record.getUserId());
             row.add(record.getOrderNo());
             row.add(record.getAmount());
@@ -247,8 +245,7 @@ public class ExportScheduler {
         queryDTO.setType(conditions[5]);
         queryDTO.setStartTime(conditions[6]);
         queryDTO.setEndTime(conditions[7]);
-        ExcelData excelData = cashOutService.excelPayDetails(queryDTO);
-        return excelData;
+        return cashOutService.excelPayDetails(queryDTO);
     }
 
     //导出保证金记录
@@ -260,9 +257,8 @@ public class ExportScheduler {
         queryDTO.setClassify(conditions[3]);
         queryDTO.setStartTime(conditions[4]);
         queryDTO.setEndTime(conditions[5]);
-        ExcelData excelData = userMoneyDetailsService.excelWalletDetails(queryDTO);
 
-        return excelData;
+        return userMoneyDetailsService.excelWalletDetails(queryDTO);
     }
 
     //导出商铺收益排行
@@ -276,4 +272,16 @@ public class ExportScheduler {
         query.setDateType(conditions[5]);
         return dataCentreService.excelShopCenter(query);
     }
+    private ExcelData getAccountEntryExcelData(ExportJob exportJob) {
+        String[] conditions=exportJob.getConditions().split(",",-1);
+        AccountEntry query =new AccountEntry();
+        query.setShopName(conditions[1]);
+        query.setShopPhone(conditions[2]);
+        query.setUserPhone(conditions[3]);
+        query.setCouponName(conditions[4]);
+        query.setOrderNumber(conditions[5]);
+        query.setStartTime(conditions[6]);
+        query.setEndTime(conditions[7]);
+        return userMoneyDetailsService.excelAccountEntry(query);
+    }
 }

+ 1 - 1
src/main/resources/application.yml

@@ -19,7 +19,7 @@ spring:
     allow-circular-references: true
   # 环境 dev|test|prod
   profiles:
-    active: prod
+    active: dev
   # jackson时间格式化
   jackson:
     time-zone: GMT+8

+ 78 - 0
src/main/resources/mapper/userMoney/UserMoneyDetailsMapper.xml

@@ -178,6 +178,7 @@
         ORDER BY umd2.id desc
         LIMIT #{limit} OFFSET #{row}
     </select>
+
     <select id="accountEntryManagementDetailsCount" resultType="java.lang.Integer">
         SELECT
         count(*)
@@ -235,4 +236,81 @@
             and umd2.create_time >= #{startTime} and #{endTime} >= umd2.create_time
         </if>
     </select>
+    <select id="excelAccountEntry" resultType="com.sqx.modules.app.entity.UserMoneyDetails">
+        SELECT
+        umd2.id,
+        umd2.orderNumber,
+        umd2.user_id as userId,
+        umd2.shop_id as shopId,
+        umd2.title,
+        umd2.content,
+        umd2.type,
+        umd2.classify,
+        umd2.money,
+        umd2.create_time as createTime,
+        umd2.state,
+        tbu.user_name as userName,
+        tbu.phone as userPhone,
+        gs.shop_name as shopName,
+        gs.phone as shopPhone,
+        tcu.coupon_name as couponName,
+        tcu.money as couponMoney,
+        apr.discount_amount as activityDiscountAmount,
+        tbo.errand_money as errandMoney
+        FROM
+        (
+        SELECT
+        RIGHT( umd.title, 18 ) AS orderNumber,
+        umd.id,
+        umd.user_id,
+        umd.shop_id,
+        umd.title,
+        umd.content,
+        umd.type,
+        umd.classify,
+        umd.money,
+        umd.create_time,
+        umd.state,
+        umd.children_id
+        FROM
+        `user_money_details` umd
+        WHERE
+        umd.type = 1
+        AND umd.classify = 3
+        AND umd.shop_id IS NOT NULL
+        AND umd.state=2
+        AND umd.title LIKE '商户订单收入' '%'
+        ) umd2
+        LEFT JOIN tb_order tbo on tbo.order_number=umd2.orderNumber
+        LEFT JOIN tb_user tbu on tbu.user_id=tbo.user_id
+        LEFT JOIN goods_shop gs on gs.shop_id=tbo.shop_id
+        LEFT JOIN tb_coupon_user tcu on tbo.coupon_id = tcu.id
+        LEFT JOIN activity_part_record apr on apr.order_id = tbo.order_id
+        where 1 = 1
+        <if test="query.shopName != null and query.shopName != ''">
+            and gs.shop_name like  concat("%", #{query.shopName}, "%")
+        </if>
+
+        <if test="query.shopPhone != null and query.shopPhone != ''">
+            and gs.phone= #{query.shopPhone}
+        </if>
+
+        <if test="query.userPhone != null and query.userPhone != ''">
+            and tbu.phone=#{query.userPhone}
+        </if>
+
+        <if test="query.couponName != null and query.couponName != ''">
+            and tcu.coupon_name like  concat("%", #{query.couponName}, "%")
+        </if>
+
+        <if test="query.orderNumber != null and query.orderNumber != ''">
+            and tbo.order_number = #{query.orderNumber}
+        </if>
+
+        <if test="query.startTime != null and query.startTime != '' and query.endTime != null and query.endTime != ''">
+            and umd2.create_time >= #{query.startTime} and #{query.endTime} >= umd2.create_time
+        </if>
+        ORDER BY umd2.id desc
+    </select>
+
 </mapper>