src/main/java/cc/mrbird/febs/mall/controller/AdminMallOrderController.java
@@ -22,6 +22,7 @@ import cc.mrbird.febs.mall.service.IAdminMallGoodsService; import cc.mrbird.febs.mall.service.IAdminMallOrderService; import cc.mrbird.febs.mall.service.IApiMallTeamLeaderService; import cc.mrbird.febs.mall.service.MallInvoiceService; import cc.mrbird.febs.mall.vo.AdminAddAddressTreeVo; import cc.mrbird.febs.mall.vo.AdminMallOrderRefundAddressVo; import cc.mrbird.febs.pay.model.OrderStateDto; @@ -661,4 +662,18 @@ return new FebsResponse().success().data(data); } private final MallInvoiceService mallInvoiceService; /** * 发票列表 * @param mallInvoiceDto * @param request * @return */ @GetMapping("invoiceList") public FebsResponse invoiceList(AdminMallInvoiceDto mallInvoiceDto, QueryRequest request) { Map<String, Object> data = getDataTable(mallInvoiceService.getInvoiceList(mallInvoiceDto, request)); return new FebsResponse().success().data(data); } } src/main/java/cc/mrbird/febs/mall/controller/ApiMallInvoiceController.java
New file @@ -0,0 +1,33 @@ package cc.mrbird.febs.mall.controller; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.mall.dto.ApiMallInvoiceDto; import cc.mrbird.febs.mall.service.MallInvoiceService; import cc.mrbird.febs.mall.vo.ApiMallInvoiceVo; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; @Slf4j @RestController @RequiredArgsConstructor @RequestMapping(value = "/api/invoice") @Api(value = "ApiMallInvoiceController", tags = "发票管理") public class ApiMallInvoiceController { private final MallInvoiceService mallInvoiceService; @ApiOperation(value = "获取发票列表", notes = "获取发票列表") @ApiResponses({ @ApiResponse(code = 200, message = "success", response = ApiMallInvoiceVo.class) }) @GetMapping(value = "/getInvoices") public FebsResponse getInvoices(@RequestBody ApiMallInvoiceDto apiMallInvoiceDto) { return mallInvoiceService.getInvoices(apiMallInvoiceDto); } } src/main/java/cc/mrbird/febs/mall/controller/ViewMallOrderController.java
@@ -255,4 +255,15 @@ return FebsUtil.view("modules/order/goodsStatistics"); } /** * 发票列表 * @return */ @GetMapping("invoiceList") @RequiresPermissions("invoiceList:view") public String invoiceList() { return FebsUtil.view("modules/order/invoiceList"); } } src/main/java/cc/mrbird/febs/mall/dto/AdminMallInvoiceDto.java
New file @@ -0,0 +1,16 @@ package cc.mrbird.febs.mall.dto; import io.swagger.annotations.ApiModel; import lombok.Data; @Data @ApiModel(value = "AdminMallInvoiceDto", description = "参数接收类") public class AdminMallInvoiceDto { private Integer state;//开票状态:0:未开票 1:开票中 2:已开票 private String orderNo; private String payOrderNo; } src/main/java/cc/mrbird/febs/mall/dto/ApiMallInvoiceDto.java
New file @@ -0,0 +1,23 @@ package cc.mrbird.febs.mall.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @Data @ApiModel(value = "ApiMallInvoiceDto", description = "参数接收类") public class ApiMallInvoiceDto { @ApiModelProperty(value = "一页数量", example = "10") private Integer pageSize; @ApiModelProperty(value = "第几页", example = "1") private Integer pageNum; @ApiModelProperty(value = "开票状态:0:未开票 1:开票中 2:已开票") private Integer state; @ApiModelProperty(hidden = true) private Long memberId; } src/main/java/cc/mrbird/febs/mall/entity/MallInvoice.java
New file @@ -0,0 +1,65 @@ package cc.mrbird.febs.mall.entity; import cc.mrbird.febs.common.entity.BaseEntity; import com.baomidou.mybatisplus.annotation.TableName; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @Data @TableName("mall_invoice") public class MallInvoice extends BaseEntity { private Long memberId; /** * fapiao_apply_id * 发票申请单号,唯一标识一次开票行为。微信支付场景下,为微信支付订单号;非微信支付场景下,为调用【获取抬头填写链接】接口时指定的发票申请单号 * 对应订单信息的pay_order_no支付订单号 */ private String fapiaoApplyId; /** *【购买方类型】 购买方类型 * 可选取值: * INDIVIDUAL: 个人 * ORGANIZATION: 单位 */ private String type; /** *【名称】 购买方名称 */ private String name; /** *【纳税人识别号】 购买方纳税人识别号,购买方类型为ORGANIZATION时必须存在 */ private String taxpayerId; /** *【地址】 购买方地址 */ private String address; /** *【电话】 购买方电话 */ private String telephone; /** *【开户银行】 购买方开户银行 */ private String bankName; /** *【银行账号】 购买方银行账号 */ private String bankAccount; /** * 匹配的订单ID */ private Long orderId; private String orderNo;//订单编号 private Integer status;//订单状态 private BigDecimal amount;//订单金额 private String goodsImg;//商品图片 private Integer state;//开票状态:0:未开票 1:开票中 2:已开票 private String invoiceUrl;//发票的URL路径 } src/main/java/cc/mrbird/febs/mall/entity/MallOrderInfo.java
@@ -132,6 +132,10 @@ * 是否送货上门 1:是 2:否 */ private Integer isHome; /** * 是否开过发票 0:未开 1:已开 */ private Integer isInvoice; @TableField(exist = false) private String orderIds; src/main/java/cc/mrbird/febs/mall/mapper/MallInvoiceMapper.java
New file @@ -0,0 +1,21 @@ package cc.mrbird.febs.mall.mapper; import cc.mrbird.febs.mall.dto.AdminMallInvoiceDto; import cc.mrbird.febs.mall.dto.ApiMallInvoiceDto; import cc.mrbird.febs.mall.entity.MallInvoice; import cc.mrbird.febs.mall.vo.ApiMallInvoiceVo; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.apache.ibatis.annotations.Param; import java.util.List; public interface MallInvoiceMapper extends BaseMapper<MallInvoice> { IPage<ApiMallInvoiceVo> selectApiMallInvoiceVoInPage(IPage<ApiMallInvoiceVo> page, @Param("record")ApiMallInvoiceDto apiMallInvoiceDto); List<MallInvoice> selectByFapiaoApplyIdAndMemberId(@Param("fapiaoApplyId")String fapiaoApplyId, @Param("memberId")Long memberId); IPage<MallInvoice> getInvoiceListInPage(Page<MallInvoice> page, @Param("record")AdminMallInvoiceDto mallInvoiceDto); } src/main/java/cc/mrbird/febs/mall/mapper/MallOrderInfoMapper.java
@@ -47,6 +47,8 @@ List<MallOrderInfo> selectOrderInfoByStatus(@Param("status") Integer status); List<MallOrderInfo> selectOrderInfoByStatusAndIsInvoice(@Param("status") Integer status,@Param("isInvoice") Integer isInvoice); List<MallOrderInfo> selectOrderInfoUpTime(@Param("status") Integer status); Integer selectCntDirectOrTeam(@Param("type") Integer type, @Param("inviteId") String inviteId); @@ -83,4 +85,6 @@ IPage<AdminGoodsStatisticsVo> getGoodsStatisticsInPage(Page<AdminGoodsStatisticsVo> page, @Param("record") MallOrderItem mallOrderItem); BigDecimal selectAmountOrTeamAmount(@Param("inviteId") String inviteId, @Param("type") Integer type); MallOrderInfo selectBypayOrderNo(@Param("payOrderNo")String payOrderNo); } src/main/java/cc/mrbird/febs/mall/quartz/WxxcxJob.java
@@ -6,6 +6,7 @@ import cc.mrbird.febs.common.utils.SpringContextHolder; import cc.mrbird.febs.mall.entity.MallMemberCoupon; import cc.mrbird.febs.mall.mapper.MallMemberCouponMapper; import cc.mrbird.febs.mall.service.MallInvoiceService; import cc.mrbird.febs.pay.util.WechatConfigure; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; @@ -37,6 +38,8 @@ private RedisUtils redisUtils; @Autowired private MallMemberCouponMapper mallMemberCouponMapper; @Autowired private MallInvoiceService mallInvoiceService; @Resource RestTemplate restTemplate; // @Autowired @@ -87,4 +90,14 @@ } /** * 更新发票记录表数据 * 定时,每天凌晨一点 * 已完成的订单,更新到发票记录中 */ @Scheduled(cron = "0 0 1 * * ?") public void mallInvoiceJob() { mallInvoiceService.mallInvoiceJob(); } } src/main/java/cc/mrbird/febs/mall/service/MallInvoiceService.java
New file @@ -0,0 +1,22 @@ package cc.mrbird.febs.mall.service; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.entity.QueryRequest; import cc.mrbird.febs.mall.dto.AdminMallInvoiceDto; import cc.mrbird.febs.mall.dto.ApiMallInvoiceDto; import cc.mrbird.febs.mall.entity.MallInvoice; import com.baomidou.mybatisplus.core.metadata.IPage; public interface MallInvoiceService { FebsResponse getInvoices(ApiMallInvoiceDto apiMallInvoiceDto); /** * 更新发票记录表数据 * 定时,每天凌晨一点 * 已完成的订单,更新到发票记录中 */ void mallInvoiceJob(); IPage<MallInvoice> getInvoiceList(AdminMallInvoiceDto mallInvoiceDto, QueryRequest request); } src/main/java/cc/mrbird/febs/mall/service/impl/MallInvoiceServiceImpl.java
New file @@ -0,0 +1,97 @@ package cc.mrbird.febs.mall.service.impl; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.entity.QueryRequest; import cc.mrbird.febs.common.enumerates.OrderStatusEnum; import cc.mrbird.febs.common.utils.LoginUserUtil; import cc.mrbird.febs.mall.dto.AdminMallInvoiceDto; import cc.mrbird.febs.mall.dto.ApiMallInvoiceDto; import cc.mrbird.febs.mall.entity.MallInvoice; import cc.mrbird.febs.mall.entity.MallMember; import cc.mrbird.febs.mall.entity.MallOrderInfo; import cc.mrbird.febs.mall.entity.MallOrderItem; import cc.mrbird.febs.mall.mapper.MallInvoiceMapper; import cc.mrbird.febs.mall.mapper.MallOrderInfoMapper; import cc.mrbird.febs.mall.mapper.MallOrderItemMapper; import cc.mrbird.febs.mall.service.MallInvoiceService; import cc.mrbird.febs.mall.vo.AdminMallOrderInfoVo; import cc.mrbird.febs.mall.vo.ApiMallInvoiceVo; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.List; @Slf4j @Service @RequiredArgsConstructor public class MallInvoiceServiceImpl extends ServiceImpl<MallInvoiceMapper, MallInvoice> implements MallInvoiceService { private final MallOrderInfoMapper mallOrderInfoMapper; private final MallOrderItemMapper mallOrderItemMapper; @Override public FebsResponse getInvoices(ApiMallInvoiceDto apiMallInvoiceDto) { MallMember member = LoginUserUtil.getLoginUser(); apiMallInvoiceDto.setMemberId(member.getId()); IPage<ApiMallInvoiceVo> page = new Page<>(apiMallInvoiceDto.getPageNum(), apiMallInvoiceDto.getPageSize()); IPage<ApiMallInvoiceVo> apiMallInvoiceVoIPage = this.baseMapper.selectApiMallInvoiceVoInPage(page, apiMallInvoiceDto); return new FebsResponse().success().data(apiMallInvoiceVoIPage); } @Override public void mallInvoiceJob() { /** * 获取当前已经是已完成且未开过发票的订单 */ List<MallOrderInfo> mallOrderInfos = mallOrderInfoMapper.selectOrderInfoByStatusAndIsInvoice(OrderStatusEnum.FINISH.getValue(), 0); if(CollUtil.isEmpty(mallOrderInfos)){ return; } for(MallOrderInfo mallOrderInfo : mallOrderInfos){ /** * 生成开票记录 */ Long memberId = mallOrderInfo.getMemberId(); /** * fapiao_apply_id * 发票申请单号,唯一标识一次开票行为。微信支付场景下,为微信支付订单号;非微信支付场景下,为调用【获取抬头填写链接】接口时指定的发票申请单号 * 对应订单信息的pay_order_no支付订单号 */ String payOrderNo = mallOrderInfo.getPayOrderNo(); List<MallInvoice> mallInvoices = this.baseMapper.selectByFapiaoApplyIdAndMemberId(payOrderNo, memberId); if(CollUtil.isNotEmpty(mallInvoices)){ continue; } MallInvoice mallInvoice = new MallInvoice(); mallInvoice.setMemberId(memberId); mallInvoice.setFapiaoApplyId(payOrderNo); mallInvoice.setOrderNo(mallOrderInfo.getOrderNo()); mallInvoice.setOrderId(mallOrderInfo.getId()); mallInvoice.setStatus(mallOrderInfo.getStatus()); mallInvoice.setAmount(mallOrderInfo.getAmount()); List<MallOrderItem> mallOrderItemList = mallOrderItemMapper.selectListByOrderId(mallOrderInfo.getId()); mallInvoice.setGoodsImg(mallOrderItemList.get(0).getSkuImage()); mallInvoice.setState(0); this.baseMapper.insert(mallInvoice); /** * 更新订单为已开票 */ mallOrderInfo.setIsInvoice(1); mallOrderInfoMapper.updateById(mallOrderInfo); } } @Override public IPage<MallInvoice> getInvoiceList(AdminMallInvoiceDto mallInvoiceDto, QueryRequest request) { Page<MallInvoice> page = new Page<>(request.getPageNum(), request.getPageSize()); return this.baseMapper.getInvoiceListInPage(page, mallInvoiceDto); } } src/main/java/cc/mrbird/febs/mall/vo/ApiMallInvoiceVo.java
New file @@ -0,0 +1,30 @@ package cc.mrbird.febs.mall.vo; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @Data @ApiModel(value = "ApiMallInvoiceVo", description = "发票") public class ApiMallInvoiceVo { @ApiModelProperty(value = "ID") private Long id; @ApiModelProperty(value = "订单编号") private String orderNo; @ApiModelProperty(value = "订单金额") private BigDecimal amount; @ApiModelProperty(value = "商品图片") private String goodsImg; @ApiModelProperty(value = "开票状态:0:未开票 1:开票中 2:已开票") private Integer state; @ApiModelProperty(value = "发票的URL路径") private String invoiceUrl; } src/main/java/cc/mrbird/febs/pay/controller/XcxPayController.java
@@ -250,6 +250,7 @@ // } /** * 微信电子发票回调接口 * POST方式回调 * @return */ @Transactional(rollbackFor = Exception.class) src/main/java/cc/mrbird/febs/pay/service/WxFaPiaoService.java
@@ -3,14 +3,10 @@ import org.springframework.web.bind.annotation.RequestBody; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.SignatureException; import java.text.ParseException; import java.util.Map; public interface WxFaPiaoService { src/main/java/cc/mrbird/febs/pay/service/impl/WxFaPiaoServiceImpl.java
@@ -3,14 +3,19 @@ import cc.mrbird.febs.common.properties.XcxProperties; import cc.mrbird.febs.common.utils.AppContants; import cc.mrbird.febs.common.utils.SpringContextHolder; import cc.mrbird.febs.mall.entity.MallInvoice; import cc.mrbird.febs.mall.entity.MallOrderInfo; import cc.mrbird.febs.mall.entity.MallOrderItem; import cc.mrbird.febs.mall.mapper.MallInvoiceMapper; import cc.mrbird.febs.mall.mapper.MallOrderInfoMapper; import cc.mrbird.febs.mall.mapper.MallOrderItemMapper; import cc.mrbird.febs.pay.model.FPCertificateVo; import cc.mrbird.febs.pay.model.FPCertificates; import cc.mrbird.febs.pay.model.FPEncryptCertificate; import cc.mrbird.febs.pay.service.WxFaPiaoService; import cc.mrbird.febs.pay.util.JCEUtil; import cc.mrbird.febs.pay.util.RandomStringGenerator; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; @@ -18,10 +23,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import okhttp3.HttpUrl; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPatch; @@ -56,6 +58,8 @@ public class WxFaPiaoServiceImpl implements WxFaPiaoService { private final MallOrderInfoMapper mallOrderInfoMapper; private final MallOrderItemMapper mallOrderItemMapper; private final MallInvoiceMapper mallInvoiceMapper; private final XcxProperties xcxProperties = SpringContextHolder.getBean(XcxProperties.class); @@ -291,7 +295,7 @@ log.info("获取到的body信息:" + body); //应对签名探测流量 if(signature.contains("WECHATPAY/SIGNTEST")){ map.put("code","500"); map.put("code",500); map.put("message", "失败"); return map; } @@ -348,8 +352,57 @@ log.info("微信电子发票回调接口....resource解密-JSONObject:"+parseObj); String fapiao_apply_id = parseObj.getStr("fapiao_apply_id"); log.info("微信电子发票回调接口....resource解密-fapiao_apply_id:"+fapiao_apply_id); MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectByOrderNo(fapiao_apply_id); MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectBypayOrderNo(fapiao_apply_id); if(ObjectUtil.isEmpty(mallOrderInfo)){ map.put("code",404); map.put("message", "订单不存在"); return map; } if(ObjectUtil.isNotEmpty(mallOrderInfo)){ //更新订单状态 mallOrderInfo.setIsInvoice(1); mallOrderInfoMapper.updateById(mallOrderInfo); //获取用户的抬头信息 String userInvoiceInfo = getUserInvoiceInfo(fapiao_apply_id); JSONObject userInvoiceInfoJson = JSONUtil.parseObj(userInvoiceInfo); //查看当前订单是否已经开具发票 Long memberId = mallOrderInfo.getMemberId(); String payOrderNo = mallOrderInfo.getPayOrderNo(); List<MallInvoice> mallInvoices = mallInvoiceMapper.selectByFapiaoApplyIdAndMemberId(fapiao_apply_id, mallOrderInfo.getMemberId()); if(CollUtil.isEmpty(mallInvoices)){ MallInvoice mallInvoice = new MallInvoice(); mallInvoice.setMemberId(memberId); mallInvoice.setFapiaoApplyId(payOrderNo); mallInvoice.setOrderNo(mallOrderInfo.getOrderNo()); mallInvoice.setOrderId(mallOrderInfo.getId()); mallInvoice.setStatus(mallOrderInfo.getStatus()); mallInvoice.setAmount(mallOrderInfo.getAmount()); List<MallOrderItem> mallOrderItemList = mallOrderItemMapper.selectListByOrderId(mallOrderInfo.getId()); mallInvoice.setGoodsImg(mallOrderItemList.get(0).getSkuImage()); mallInvoice.setState(1); mallInvoice.setType(userInvoiceInfoJson.getStr("type")); mallInvoice.setName(userInvoiceInfoJson.getStr("name")); mallInvoice.setTaxpayerId(userInvoiceInfoJson.getStr("taxpayer_id")); mallInvoice.setAddress(userInvoiceInfoJson.getStr("address")); mallInvoice.setTelephone(userInvoiceInfoJson.getStr("telephone")); mallInvoice.setBankName(userInvoiceInfoJson.getStr("bank_name")); mallInvoice.setBankAccount(userInvoiceInfoJson.getStr("bank_account")); mallInvoiceMapper.insert(mallInvoice); }else{ MallInvoice mallInvoice = mallInvoices.get(0); if(2 != mallInvoice.getState()){ mallInvoice.setState(1); mallInvoice.setType(userInvoiceInfoJson.getStr("type")); mallInvoice.setName(userInvoiceInfoJson.getStr("name")); mallInvoice.setTaxpayerId(userInvoiceInfoJson.getStr("taxpayer_id")); mallInvoice.setAddress(userInvoiceInfoJson.getStr("address")); mallInvoice.setTelephone(userInvoiceInfoJson.getStr("telephone")); mallInvoice.setBankName(userInvoiceInfoJson.getStr("bank_name")); mallInvoice.setBankAccount(userInvoiceInfoJson.getStr("bank_account")); mallInvoiceMapper.updateById(mallInvoice); } } //省略查询订单 //此处处理业务 map.put("code","SUCCESS"); @@ -358,17 +411,55 @@ return map; } } map.put("code","RESOURCE_NOT_EXISTS"); map.put("code",404); map.put("message", "订单不存在"); return map; }catch (Exception e) { e.printStackTrace(); } } map.put("code","500"); map.put("code",500); map.put("message", "失败"); return map; } /** * 获取用户的抬头信息 */ public String getUserInvoiceInfo(String fapiaoApplyId) throws IOException { //初始化请求参数 Map<String, Object> params = new HashMap<>(); params.put("scene","WITH_WECHATPAY"); params.put("fapiao_apply_id","4200002070202401175245187105"); String baseUrl = "https://api.mch.weixin.qq.com"; String canonicalUrl = "/v3/new-tax-control-fapiao/user-title"; String urlparm = baseUrl+canonicalUrl;//有参数的get请求,加密是需要把参数加载进去URL List<BasicNameValuePair> parameters = new ArrayList<>(); for (Map.Entry<String, Object> entry : params.entrySet()) { parameters.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString())); } StringBuilder dataparm = new StringBuilder(); params.forEach((k, v) -> dataparm.append("&" + k + "=" + v)); String string = dataparm.toString(); if (!"".equals(string)) { urlparm = baseUrl+canonicalUrl + "?" + dataparm.substring(1); } PrivateKey privateKey = this.getPrivateKeyV3(); String postStr = null; try { postStr = this.createAuthorization( "GET", urlparm, "", privateKey ); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return this.sendGet(baseUrl+canonicalUrl, params, "WECHATPAY2-SHA256-RSA2048 "+postStr); } /** * 验证签名 src/main/resources/mapper/modules/MallInvoiceMapper.xml
New file @@ -0,0 +1,51 @@ <?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="cc.mrbird.febs.mall.mapper.MallInvoiceMapper"> <select id="selectApiMallInvoiceVoInPage" resultType="cc.mrbird.febs.mall.vo.ApiMallInvoiceVo"> select a.id, a.order_no, a.amount, a.goods_img, a.state, a.invoice_url from mall_invoice a <where> <if test="record.memberId != null"> and a.member_id=#{record.memberId} </if> <if test="record.state != null"> and a.state=#{record.state} </if> </where> order by a.created_time desc </select> <select id="selectByFapiaoApplyIdAndMemberId" resultType="cc.mrbird.febs.mall.entity.MallInvoice"> select a.* from mall_invoice a where fapiao_apply_id = #{fapiaoApplyId} and member_id = #{memberId} </select> <select id="getInvoiceListInPage" resultType="cc.mrbird.febs.mall.entity.MallInvoice"> select a.* from mall_invoice a <where> <if test="record.state != null"> and a.state = #{record.state} </if> <if test="record.orderNo != null"> and a.order_no = #{record.orderNo} </if> <if test="record.payOrderNo != null"> and a.fapiao_apply_id = #{record.payOrderNo} </if> </where> order by a.created_time desc </select> </mapper> src/main/resources/mapper/modules/MallOrderInfoMapper.xml
@@ -233,6 +233,10 @@ select * from mall_order_info where status=#{status} </select> <select id="selectOrderInfoByStatusAndIsInvoice" resultType="cc.mrbird.febs.mall.entity.MallOrderInfo"> select * from mall_order_info where status = #{status} and is_invoice = #{isInvoice} </select> <select id="selectOrderInfoUpTime" resultType="cc.mrbird.febs.mall.entity.MallOrderInfo"> select * from mall_order_info where status=#{status} and now() > date_add(order_time,interval 1440 minute) </select> @@ -458,4 +462,8 @@ </if> </where> </select> <select id="selectBypayOrderNo" resultType="cc.mrbird.febs.mall.entity.MallOrderInfo"> select * from mall_order_info where pay_order_no = #{payOrderNo} </select> </mapper> src/main/resources/templates/febs/views/modules/order/invoiceList.html
New file @@ -0,0 +1,276 @@ <div class="layui-fluid layui-anim febs-anim" id="febs-invoice" lay-title="发票管理"> <div class="layui-row febs-container"> <div class="layui-col-md12"> <div class="layui-card"> <div class="layui-card-body febs-table-full"> <form class="layui-form layui-table-form" lay-filter="user-table-form"> <div class="layui-form-item"> <div class="layui-col-md10"> <div class="layui-inline"> <label class="layui-form-label">编号:</label> <div class="layui-input-inline"> <input type="text" placeholder="发票申请单号/微信支付订单号" name="payOrderNo" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label">订单编号:</label> <div class="layui-input-inline"> <input type="text" placeholder="订单编号" name="orderNo" autocomplete="off" class="layui-input"> </div> </div> <div class="layui-inline"> <label class="layui-form-label layui-form-label-sm">状态:</label> <div class="layui-input-inline"> <select name="state"> <option value="">请选择</option> <option value="0">未开票</option> <option value="1">开票中</option> <option value="2">已开票</option> </select> </div> </div> </div> <div class="layui-col-md2 layui-col-sm12 layui-col-xs12 table-action-area"> <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-blue-plain table-action" id="query"> <i class="layui-icon"></i> </div> <div class="layui-btn layui-btn-sm layui-btn-primary febs-button-green-plain table-action" id="reset"> <i class="layui-icon"></i> </div> </div> </div> </form> <table lay-filter="invoiceTable" lay-data="{id: 'invoiceTable'}"></table> <style type="text/css"> .layui-table cell{ text-align:center; height: auto; white-space: nowrap; /*文本不会换行,在同一行显示*/ overflow: hidden; /*超出隐藏*/ text-overflow: ellipsis; /*省略号显示*/ } .layui-table img{ max-width:100px } ::-webkit-scrollbar { height: 20px !important; background-color: #f4f4f4; } </style> </div> </div> </div> </div> </div> <!-- 表格操作栏 start --> <script type="text/html" id="user-option"> <span shiro:lacksPermission="user:view,user:update,user:delete"> <span class="layui-badge-dot febs-bg-orange"></span> 无权限 </span> <a lay-event="edit" shiro:hasPermission="user:update"><i class="layui-icon febs-edit-area febs-blue"></i></a> </script> <!-- 表格操作栏 end --> <script data-th-inline="none" type="text/javascript"> // 引入组件并初始化 layui.use([ 'jquery', 'form', 'table', 'febs', 'formSelects', 'upload','laydate'], function () { var $ = layui.jquery, febs = layui.febs, form = layui.form, table = layui.table, upload = layui.upload, $view = $('#febs-invoice'), $query = $view.find('#query'), $reset = $view.find('#reset'), $searchForm = $view.find('form'), $add = $view.find('#add'), sortObject = {field: 'orderTime', type: 'desc'}, formSelects = layui.formSelects, laydate = layui.laydate, tableIns; let currPageOrder = 1;//首先默认值为1,防止出错 //获取当前页 currPageOrder = $view.find(".layui-laypage-em").next().html(); form.render(); formSelects.render(); // 表格初始化 initInvoiceTable(); upload.render({ elem: '#importDeliver' ,url: 'admin/order/importDeliver' //此处配置你自己的上传接口即可 ,accept: 'file' //普通文件 ,done: function(res){ console.log("123"); febs.alert.success('操作成功'); $query.click(); } }); // 初始化表格操作栏各个按钮功能 table.on('tool(invoiceTable)', function (obj) { var data = obj.data, layEvent = obj.event; if (layEvent === 'deliverGoods') { febs.modal.open('发货', 'modules/order/deliverGoods/' + data.id, { btn: ['确认','取消'], yes: function (index, layero) { $('#deliver-update').find('#submit').trigger('click'); // $query.click(); }, btn2: function () { layer.closeAll(); } }); } if (layEvent === 'updateDeliver') { febs.modal.open('修改物流信息', 'modules/order/deliverGoods/' + data.id, { btn: ['确认','取消'], yes: function (index, layero) { $('#deliver-update').find('#deliverInfoSubmit').trigger('click'); // $query.click(); }, btn2: function () { layer.closeAll(); } }); } if (layEvent === 'seeOrder') { febs.modal.open( '订单详情', 'modules/order/orderDetail/' + data.id, { maxmin: true, }); } if (layEvent === 'cancelOrder') { febs.modal.confirm('取消订单', '确认取消订单?', function () { cancelOrder(data.id); }); } if (layEvent === 'seePayImage') { var t = $view.find('#seePayImage'+data.id+''); //页面层 layer.open({ type: 1, title: "支付凭证", skin: 'layui-layer-rim', //加上边框 area: ['80%', '80%'], //宽高 shadeClose: true, //开启遮罩关闭 end: function (index, layero) { return false; }, content: '<div style="text-align:center"><img src="' + $(t).attr('src') + '" /></div>' }); } }); function cancelOrder(id) { febs.get(ctx + 'admin/order/cancelOrder/' + id, null, function () { febs.alert.success('操作成功'); $query.click(); }); } // 查询按钮 $query.on('click', function () { var params = $.extend(getQueryParams(), {field: sortObject.field, order: sortObject.type}); tableIns.reload({where: params, page: {curr: currPageOrder}}); }); // 刷新按钮 $reset.on('click', function () { $searchForm[0].reset(); sortObject.type = 'null'; tableIns.reload({where: getQueryParams(), page: {curr: currPageOrder}, initSort: sortObject}); }); function initInvoiceTable() { tableIns = febs.table.init({ elem: $view.find('table'), id: 'invoiceTable', url: ctx + 'admin/order/invoiceList', defaultToolbar: [], //系统自带打印导出 totalRow : true, cols: [[ {field: 'orderNo', title: '订单编号', minWidth: 100,align:'left' ,totalRowText:"合计"}, {field: 'fapiaoApplyId', title: '发票申请单号', minWidth: 150,align:'left'}, {field: 'type', title: '购买方类型', templet: function (d) { if (d.type === 'INDIVIDUAL') { return '<span style="color:red;">个人</span>' } else if (d.status === 'ORGANIZATION') { return '<span style="color:green;">单位</span>' }else{ return '' } }, minWidth: 80,align:'center'}, {field: 'name', title: '名称', minWidth: 120,align:'left'}, {field: 'taxpayerId', title: '纳税人识别号', minWidth: 100,align:'left'}, {field: 'address', title: '地址', minWidth: 200,align:'left'}, {field: 'telephone', title: '电话', minWidth: 100,align:'left'}, {field: 'bankName', title: '开户银行', minWidth: 100,align:'left', totalRow:true}, {field: 'bankAccount', title: '银行账号', minWidth: 100,align:'left', totalRow:true}, {field: 'state', title: '状态', templet: function (d) { if (d.state === 0) { return '<span style="color:red;">待申请</span>' } else if (d.state === 1) { return '<span style="color:green;">待开票</span>' }else if (d.state === 2) { return '<span style="color:green;">已开票</span>' }else{ return '' } }, minWidth: 100,align:'center'}, {field: 'status', title: '订单状态', templet: function (d) { if (d.status === 1) { return '<span style="color:red;">待支付</span>' } else if (d.status === 2) { return '<span style="color:green;">待发货</span>' }else if (d.status === 3) { return '<span style="color:green;">待收货</span>' }else if (d.status === 4) { return '<span style="color:green;">已完成</span>' }else if (d.status === 5) { return '<span style="color:green;">退款中</span>' }else if (d.status === 6) { return '<span style="color:green;">已退款</span>' }else if (d.status === 7) { return '<span style="color:green;">已取消</span>' }else{ return '' } }, minWidth: 100,align:'center'}, {title: '操作', templet: function (d) { if(d.status === 2){ return '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="seeOrder" shiro:hasPermission="user:update">详情</button>' +'<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="deliverGoods" shiro:hasPermission="user:update">发货</button>' }else if(d.status === 3){ return '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="seeOrder" shiro:hasPermission="user:update">详情</button>' +'<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="updateDeliver" shiro:hasPermission="user:update">修改物流信息</button>' }else{ return '<button class="layui-btn layui-btn-normal layui-btn-xs" lay-event="seeOrder" shiro:hasPermission="user:update">详情</button>' } },minWidth: 200,align:'center', fixed:'right'} ]] }); } // 获取查询参数 function getQueryParams() { return { orderNo: $searchForm.find('input[name="orderNo"]').val().trim(), payOrderNo: $searchForm.find('input[name="payOrderNo"]').val().trim(), state: $searchForm.find("select[name='state']").val(), }; } }) </script> src/test/java/cc/mrbird/febs/ProfitTest.java
@@ -202,8 +202,6 @@ Map<String, Object> params = new HashMap<>(); params.put("scene","WITH_WECHATPAY"); params.put("fapiao_apply_id","4200002070202401175245187105"); String parseObj = JSONUtil.parseObj(params).toString(); System.out.println(parseObj); String baseUrl = "https://api.mch.weixin.qq.com"; String canonicalUrl = "/v3/new-tax-control-fapiao/user-title"; @@ -219,8 +217,6 @@ if (!"".equals(string)) { urlparm = baseUrl+canonicalUrl + "?" + dataparm.substring(1); } System.out.println(urlparm); PrivateKey privateKey = wxFaPiaoService.getPrivateKeyV3(); String postStr = null; try { @@ -235,7 +231,7 @@ } String s = wxFaPiaoService.sendGet(baseUrl+canonicalUrl, params, "WECHATPAY2-SHA256-RSA2048 "+postStr); System.out.println(s); } } @Test public void rankProfit2() throws IOException {//查询配置开发选项