feat: 积分商城-对账-发票-优化

This commit is contained in:
2026-09-03 18:19:03 +08:00
parent 72dfff50a6
commit 9159f8912d
14 changed files with 558 additions and 234 deletions
@@ -11,7 +11,7 @@ public class PointsMallInvoiceApplyParam {
private String endDate;
private String invoiceDate;
private String invoiceTitle;
private String invoiceCode;
private String taxIdNumber;
private String invoiceAddress;
private String invoiceContact;
private Integer invoiceType;
@@ -6,13 +6,15 @@ import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceInfo;
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceMain;
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceApplyParam;
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceInfoPageParam;
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceMainPageParam;
import com.budwk.app.zhgh.pointsmall.invoice.param.PointsMallInvoiceOrderPageParam;
import com.budwk.app.zhgh.pointsmall.invoice.service.PointsMallInvoiceService;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallInvoiceApplyDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.service.MallInvoiceApplyOutboundService;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
import org.nutz.dao.Chain;
@@ -21,6 +23,7 @@ import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Record;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import java.math.BigDecimal;
@@ -30,6 +33,9 @@ import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"})
public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvoiceMain> implements PointsMallInvoiceService {
@Inject
private MallInvoiceApplyOutboundService mallInvoiceApplyOutboundService;
public PointsMallInvoiceServiceImpl(Dao dao) {
super(dao);
}
@@ -38,7 +44,7 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
public Pagination<PointsMallInvoiceMain> mainPage(PointsMallInvoiceMainPageParam param) {
Cnd cnd = Cnd.where("delFlag", "=", false);
if (StrUtil.isNotBlank(param.getSettlementId())) {
cnd.and("settlementId", "like", "%" + param.getSettlementId() + "%");
cnd.and("settlementId", "=", param.getSettlementId());
}
if (param.getBSuccess() != null) {
cnd.and("bSuccess", "=", param.getBSuccess());
@@ -63,10 +69,10 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
cnd.and("mainId", "=", param.getMainId());
}
if (StrUtil.isNotBlank(param.getInvoiceId())) {
cnd.and("invoiceId", "like", "%" + param.getInvoiceId() + "%");
cnd.and("invoiceId", "=", param.getInvoiceId());
}
if (StrUtil.isNotBlank(param.getInvoiceCode())) {
cnd.and("invoiceCode", "like", "%" + param.getInvoiceCode() + "%");
cnd.and("invoiceCode", "=", param.getInvoiceCode());
}
if (StrUtil.isNotBlank(param.getInvoiceDate())) {
cnd.and("invoiceDate", "=", DateUtil.parse(param.getInvoiceDate()));
@@ -132,24 +138,37 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
invoice.setFailMsg("");
insert(invoice);
PointsMallInvoiceInfo info = new PointsMallInvoiceInfo();
info.setMainId(invoice.getId());
info.setInvoiceId(settlementId);
info.setInvoiceCode(param.getInvoiceCode());
info.setInvoiceDate(DateUtil.parse(param.getInvoiceDate()));
info.setInvoiceType(param.getInvoiceType());
info.setInvoiceAmount(orderTotalPoints(query));
info.setInvoiceNakeAmount(info.getInvoiceAmount());
info.setInvoiceAddress(param.getInvoiceAddress());
info.setInvoiceContact(param.getInvoiceContact());
info.setInvoiceContent(param.getInvoiceContent());
info.setTaxIdNumber(param.getInvoiceCode());
info.setRemark(param.getRemark());
info.setInvoiceBank(param.getBankName());
info.setInvoiceAccount(param.getBankAccount());
dao().insert(info);
MallInvoiceApplyDTO dto = new MallInvoiceApplyDTO();
dto.setSupplierId(param.getSupplierId());
dto.setSettlementId(settlementId);
dto.setOrderIds(String.join(",", orderIds));
dto.setOrderNum(orders.size());
dto.setOrderTotalPrice(orders.stream().map(PointsMallOrderSub::getTotalPrice)
.filter(java.util.Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
dto.setInvoiceDate(param.getInvoiceDate());
dto.setInvoiceTitle(param.getInvoiceTitle());
dto.setTaxIdNumber(param.getTaxIdNumber());
dto.setInvoiceAddress(param.getInvoiceAddress());
dto.setInvoiceContact(param.getInvoiceContact());
dto.setInvoiceType(param.getInvoiceType() == null ? null : String.valueOf(param.getInvoiceType()));
dto.setInvoiceContent(param.getInvoiceContent());
dto.setRemark(param.getRemark());
dto.setBankAccount(param.getBankAccount());
dto.setRegisteredAddress(param.getRegisteredAddress());
dto.setBankName(param.getBankName());
dao().update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 2), Cnd.where("supplierId", "=", param.getSupplierId()).and("orderId", "in", orderIds));
MallOutboundResult result = mallInvoiceApplyOutboundService.applyInvoice(dto);
if (result == null || result.getResultCode() != 0) {
invoice.setBSuccess(1);
invoice.setSucOrderIds("");
invoice.setFailOrderIds(String.join(",", orderIds));
invoice.setFailMsg(result == null ? "供应商开票申请无响应" : result.getMessage());
updateIgnoreNull(invoice);
throw new IllegalArgumentException(invoice.getFailMsg());
}
dao().update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 2).add("invoiceCode", settlementId),
Cnd.where("supplierId", "=", param.getSupplierId()).and("orderId", "in", orderIds));
return "开票申请已生成,结算单号:" + settlementId;
}
@@ -205,7 +224,10 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
if (StrUtil.isBlank(param.getInvoiceDate())) {
throw new IllegalArgumentException("开票日期不能为空");
}
if (StrUtil.isBlank(param.getInvoiceCode())) {
if (StrUtil.isBlank(param.getInvoiceTitle())) {
throw new IllegalArgumentException("发票抬头不能为空");
}
if (StrUtil.isBlank(param.getTaxIdNumber())) {
throw new IllegalArgumentException("纳税人识别号不能为空");
}
if (StrUtil.isBlank(param.getInvoiceAddress())) {
@@ -214,5 +236,8 @@ public class PointsMallInvoiceServiceImpl extends BaseServiceImpl<PointsMallInvo
if (StrUtil.isBlank(param.getInvoiceContact())) {
throw new IllegalArgumentException("联系电话不能为空");
}
if (param.getInvoiceType() == null) {
throw new IllegalArgumentException("发票类型不能为空");
}
}
}
@@ -1,5 +1,7 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.controller;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.pointsmall.mallbridge.annotation.MallTokenRequired;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.*;
@@ -13,6 +15,7 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.integration.jedis.RedisService;
import org.nutz.mvc.adaptor.JsonAdaptor;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At;
@@ -32,6 +35,25 @@ public class PointsMallBridgeController {
@Inject
private PointsMallBridgeService pointsMallBridgeService;
@Inject
private RedisService redisService;
@POST
@At("/connect/supplier-session")
@ApiOperation(value = "获取供应商用户会话", notes = "使用 H5 跳转 keyword 换取一次性用户会话")
public Result supplierSession(@Param("..") MallSupplierSessionDTO dto) {
if (dto == null || StrUtil.isBlank(dto.getKeyword())) {
return Result.error("keyword不能为空");
}
String redisKey = "supplier-session:" + dto.getKeyword();
String session = redisService.get(redisKey);
if (StrUtil.isBlank(session)) {
return Result.error("用户会话不存在或已失效");
}
redisService.del(redisKey);
return Result.success(JSONUtil.parseObj(session));
}
@POST
@At("/connect/token")
@ApiOperation(value = "获取 token", notes = "供应商获取访问令牌")
@@ -14,7 +14,7 @@ public class MallInvoiceApplyDTO {
private BigDecimal orderTotalPrice;
private String invoiceDate;
private String invoiceTitle;
private String invoiceCode;
private String taxIdNumber;
private String invoiceAddress;
private String invoiceContact;
private BigDecimal invoiceNakedPrice;
@@ -0,0 +1,8 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
import lombok.Data;
@Data
public class MallSupplierSessionDTO {
private String keyword;
}
@@ -1,12 +1,18 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceInfo;
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceMain;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.GetInvoiceInfoDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.InvoiceInfoDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderQueryDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderInfoDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderProInfoDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.QueryInvoiceInfoDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.event.MallOrderEventHandler;
import com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers.MallAbolishSubOrderEventHandler;
import com.budwk.app.zhgh.pointsmall.mallbridge.event.handlers.MallCancelPayedMainOrderEventHandler;
@@ -54,6 +60,8 @@ public class MallInboundEventService extends AbstractMallBridgeSupport {
@Inject
private MallOrderQueryOutboundService mallOrderQueryOutboundService;
@Inject
private MallInvoiceInfoQueryService mallInvoiceInfoQueryService;
@Inject
private MallCancelPendingOrderEventHandler mallCancelPendingOrderEventHandler;
@Inject
private MallSplitSubOrderEventHandler mallSplitSubOrderEventHandler;
@@ -416,13 +424,73 @@ public class MallInboundEventService extends AbstractMallBridgeSupport {
}
public MallInboundResult invoiceInfo(MallOrderEventDTO dto) {
String mainOrderId = StrUtil.blankToDefault(dto.getMainOrderId(), dto.getOrderId());
if (StrUtil.isBlank(mainOrderId)) {
return MallInboundResult.fail(400, "主订单信息不能为空");
String settlementId = dto.getOrderId();
if (StrUtil.hasBlank(dto.getSupplierId(), settlementId)) {
return MallInboundResult.fail(400, "供应商和结算单号不能为空");
}
dao.update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 1), Cnd.where("supplierId", "=", dto.getSupplierId())
.and("mainOrderId", "=", mainOrderId).and("delFlag", "=", false));
log.info("积分商城发票通知状态更新完成,supplierId={}mainOrderId={}", dto.getSupplierId(), mainOrderId);
QueryInvoiceInfoDTO query = new QueryInvoiceInfoDTO();
query.setSupplierId(dto.getSupplierId());
query.setSettlementId(settlementId);
GetInvoiceInfoDTO result;
try {
result = mallInvoiceInfoQueryService.queryInvoicesInfo(query);
} catch (Exception e) {
log.error("调用供应商获取发票信息失败,supplierId={}settlementId={}", dto.getSupplierId(), settlementId, e);
return MallInboundResult.fail(-1, "获取供应商发票信息失败");
}
PointsMallInvoiceMain main = dao.fetch(PointsMallInvoiceMain.class,
Cnd.where("settlementId", "=", settlementId).and("delFlag", "=", false));
if (main == null) {
return MallInboundResult.fail(404, "开票申请记录不存在");
}
Integer success = result.getBSuccess() == null ? 0 : result.getBSuccess();
main.setBSuccess(success);
main.setSucOrderIds(result.getSucOrderIds());
main.setFailOrderIds(result.getFailOrderIds());
main.setFailMsg(result.getFailMsg());
dao.updateIgnoreNull(main);
if (success == 0 && result.getInvoiceInfos() != null) {
for (InvoiceInfoDTO item : result.getInvoiceInfos()) {
PointsMallInvoiceInfo info = dao.fetch(PointsMallInvoiceInfo.class,
Cnd.where("mainId", "=", main.getId()).and("invoiceId", "=", item.getInvoiceId()).and("delFlag", "=", false));
if (info == null) {
info = new PointsMallInvoiceInfo();
info.setMainId(main.getId());
info.setInvoiceId(item.getInvoiceId());
}
info.setInvoiceCode(item.getInvoiceCode());
info.setInvoiceDate(item.getInvoiceDate() == null ? null : DateUtil.parse(item.getInvoiceDate().toString()));
info.setInvoiceNakeAmount(item.getInvoiceNakeAmount());
info.setInvoiceTaxRate(item.getInvoiceTaxRate());
info.setInvoiceTaxAmount(item.getInvoiceTaxAmount());
info.setInvoiceAmount(item.getInvoiceAmount());
info.setInvoiceType(item.getInvoiceType());
info.setUrl(item.getUrl());
info.setImageEncode(item.getImageEncode());
info.setFileType(item.getFileType());
info.setCheckCode(item.getCheckCode());
info.setInvoiceAddress(item.getInvoiceAddress());
if (StrUtil.isBlank(info.getId())) {
dao.insert(info);
} else {
dao.updateIgnoreNull(info);
}
}
}
List<String> successOrderIds = splitIds(result.getSucOrderIds());
List<String> failOrderIds = splitIds(result.getFailOrderIds());
if (!successOrderIds.isEmpty()) {
dao.update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 1), Cnd.where("supplierId", "=", dto.getSupplierId())
.and("orderId", "in", successOrderIds).and("delFlag", "=", false));
}
if (!failOrderIds.isEmpty()) {
dao.update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 0), Cnd.where("supplierId", "=", dto.getSupplierId())
.and("orderId", "in", failOrderIds).and("delFlag", "=", false));
}
log.info("供应商发票信息更新完成,supplierId={}settlementId={}", dto.getSupplierId(), settlementId);
return MallInboundResult.success();
}
}
@@ -1,24 +1,21 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
import cn.hutool.core.convert.Convert;
import cn.hutool.http.HttpUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceInfo;
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceMain;
import cn.hutool.json.JSONUtil;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallInvoiceApplyDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
import com.budwk.app.zhgh.pointsmall.mallbridge.util.MallBridgeCryptoUtil;
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.trans.Atom;
import org.nutz.trans.Trans;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import java.util.HashMap;
/**
* 商城桥接开票申请出站服务。
@@ -27,73 +24,61 @@ import java.util.Objects;
@IocBean(args = {"refer:dao"})
public class MallInvoiceApplyOutboundService extends AbstractMallBridgeSupport {
@Inject
private PropertiesProxy conf;
public MallInvoiceApplyOutboundService(Dao dao) {
super(dao);
}
/**
* 接收开票申请并保存开票记录
* 向供应商发起开票申请
*/
public MallOutboundResult applyInvoice(MallInvoiceApplyDTO dto) {
if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getSettlementId(), dto.getOrderIds())) {
return MallOutboundResult.fail(400, "开票申请参数不能为空");
}
List<String> orderIds = splitIds(dto.getOrderIds());
log.info("积分商城开票申请开始,supplierId={}settlementId={}orderCount={}", dto.getSupplierId(), dto.getSettlementId(), orderIds.size());
List<PointsMallOrderSub> orders = dao.query(PointsMallOrderSub.class, Cnd.where("supplierId", "=", dto.getSupplierId())
.and("orderId", "in", orderIds).and("delFlag", "=", false));
if (orders.isEmpty()) {
return MallOutboundResult.fail(404, "未找到可开票订单");
String clientBAB7ServerUrl = conf.get("spdb.bab7.url", "");
if (StrUtil.isBlank(clientBAB7ServerUrl)) {
return MallOutboundResult.fail(500, "未配置 BAB7 服务地址");
}
if (dto.getOrderNum() != null && dto.getOrderNum() != orders.size()) {
return MallOutboundResult.fail(400, "订单数量与开票申请不一致");
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class,
Cnd.where("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false));
if (supplier == null) {
return MallOutboundResult.fail(404, "未找到对应供应商信息");
}
BigDecimal total = orders.stream().map(PointsMallOrderSub::getTotalPrice).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
if (dto.getOrderTotalPrice() != null && total.compareTo(dto.getOrderTotalPrice()) != 0) {
return MallOutboundResult.fail(400, "订单金额与开票申请不一致");
if (StrUtil.isBlank(supplier.getSupplierApiUrl())) {
return MallOutboundResult.fail(404, "供应商地址未配置");
}
Trans.exec((Atom) () -> saveInvoiceApply(dto, orderIds, total));
log.info("积分商城开票申请完成,supplierId={}settlementId={}", dto.getSupplierId(), dto.getSettlementId());
return MallOutboundResult.success();
}
long timestamp = System.currentTimeMillis();
dto.setToken(MallBridgeCryptoUtil.generateSign(supplier.getSupplierId(), supplier.getClientId(), timestamp));
dto.setTimestamp(timestamp);
private void saveInvoiceApply(MallInvoiceApplyDTO dto, List<String> orderIds, BigDecimal total) {
PointsMallInvoiceMain main = dao.fetch(PointsMallInvoiceMain.class, Cnd.where("settlementId", "=", dto.getSettlementId()).and("delFlag", "=", false));
if (main == null) {
main = new PointsMallInvoiceMain();
main.setSettlementId(dto.getSettlementId());
main.setBSuccess(0);
main.setSucOrderIds(String.join(",", orderIds));
main.setFailOrderIds("");
main.setFailMsg("");
dao.insert(main);
} else {
main.setBSuccess(0);
main.setSucOrderIds(String.join(",", orderIds));
main.setFailOrderIds("");
main.setFailMsg("");
dao.updateIgnoreNull(main);
String keyHex = conf.get("sm4cbc.keyHex", "");
String ivHex = conf.get("sm4cbc.ivHex", "");
String encrypt;
try {
encrypt = MallBridgeCryptoUtil.sm4CbcEncrypt(JSONUtil.toJsonStr(dto), keyHex, ivHex);
} catch (Exception e) {
log.error("9.2.5 发票开具申请接口请求参数 SM4CBC 加密出错", e);
return MallOutboundResult.fail(500, "发票开具申请参数加密失败");
}
PointsMallInvoiceInfo info = new PointsMallInvoiceInfo();
info.setMainId(main.getId());
info.setInvoiceId(dto.getSettlementId());
info.setInvoiceCode(dto.getInvoiceCode());
info.setInvoiceDate(parseDate(dto.getInvoiceDate()));
info.setInvoiceNakeAmount(nvl(dto.getInvoiceNakedPrice(), total));
info.setInvoiceTaxAmount(nvl(dto.getInvoiceTaxPrice(), BigDecimal.ZERO));
info.setInvoiceAmount(total);
info.setInvoiceType(Convert.toInt(dto.getInvoiceType(), null));
info.setInvoiceAddress(dto.getInvoiceAddress());
info.setInvoiceContact(dto.getInvoiceContact());
info.setInvoiceContent(dto.getInvoiceContent());
info.setInvoiceBank(dto.getBankName());
info.setInvoiceAccount(dto.getBankAccount());
info.setTaxIdNumber(dto.getInvoiceCode());
info.setRemark(dto.getRemark());
dao.insert(info);
HashMap<String, Object> bodyMap = new HashMap<>();
bodyMap.put("Address4", supplier.getSupplierApiUrl() + "/supplierOpenApi/pointOrder/applyForInvoices");
bodyMap.put("BussDealMd", "P");
bodyMap.put("SroNo", supplier.getSroNo());
bodyMap.put("RsrvFld1", supplier.getClientId());
bodyMap.put("AplParmObjct", encrypt);
dao.update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 2).add("invoiceCode", dto.getSettlementId()),
Cnd.where("supplierId", "=", dto.getSupplierId()).and("orderId", "in", orderIds));
String response = HttpUtil.createPost(clientBAB7ServerUrl)
.contentType("application/json;charset=UTF-8")
.body(JSONUtil.toJsonStr(bodyMap))
.execute()
.body();
if (StrUtil.isBlank(response)) {
return MallOutboundResult.fail(502, "供应商开票申请无响应");
}
return JSONUtil.toBean(response, MallOutboundResult.class);
}
}
@@ -1,19 +1,22 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.service;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceInfo;
import com.budwk.app.zhgh.pointsmall.invoice.models.PointsMallInvoiceMain;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.GetInvoiceInfoDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.InvoiceInfoDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.QueryInvoiceInfoDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.service.support.AbstractMallBridgeSupport;
import com.budwk.app.zhgh.pointsmall.mallbridge.util.MallBridgeCryptoUtil;
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
import lombok.extern.slf4j.Slf4j;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.impl.PropertiesProxy;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import java.util.List;
import java.util.stream.Collectors;
import java.util.HashMap;
/**
* 商城桥接发票信息查询服务。
@@ -22,6 +25,9 @@ import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"})
public class MallInvoiceInfoQueryService extends AbstractMallBridgeSupport {
@Inject
private PropertiesProxy conf;
public MallInvoiceInfoQueryService(Dao dao) {
super(dao);
}
@@ -33,21 +39,57 @@ public class MallInvoiceInfoQueryService extends AbstractMallBridgeSupport {
if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getSettlementId())) {
throw new IllegalArgumentException("发票查询参数不能为空");
}
log.info("积分商城查询发票信息,supplierId={}settlementId={}", dto.getSupplierId(), dto.getSettlementId());
PointsMallInvoiceMain main = dao.fetch(PointsMallInvoiceMain.class, Cnd.where("settlementId", "=", dto.getSettlementId())
.and("delFlag", "=", false));
if (main == null) {
throw new IllegalArgumentException("发票信息不存在");
String clientBAB7ServerUrl = conf.get("spdb.bab7.url", "");
if (StrUtil.isBlank(clientBAB7ServerUrl)) {
throw new IllegalArgumentException("未配置 BAB7 服务地址");
}
List<InvoiceInfoDTO> invoiceInfos = dao.query(PointsMallInvoiceInfo.class, Cnd.where("mainId", "=", main.getId()).and("delFlag", "=", false))
.stream().map(this::toInvoiceInfoDTO).collect(Collectors.toList());
GetInvoiceInfoDTO result = new GetInvoiceInfoDTO();
result.setBSuccess(main.getBSuccess());
result.setSettlementId(main.getSettlementId());
result.setSucOrderIds(main.getSucOrderIds());
result.setFailOrderIds(main.getFailOrderIds());
result.setFailMsg(main.getFailMsg());
result.setInvoiceInfos(invoiceInfos);
return result;
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class,
Cnd.where("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false));
if (supplier == null) {
throw new IllegalArgumentException("未找到对应供应商信息");
}
if (StrUtil.isBlank(supplier.getSupplierApiUrl())) {
throw new IllegalArgumentException("供应商地址未配置");
}
long timestamp = System.currentTimeMillis();
dto.setToken(MallBridgeCryptoUtil.generateSign(supplier.getSupplierId(), supplier.getClientId(), timestamp));
dto.setTimestamp(timestamp);
String encrypt;
try {
encrypt = MallBridgeCryptoUtil.sm4CbcEncrypt(
JSONUtil.toJsonStr(dto),
conf.get("sm4cbc.keyHex", ""),
conf.get("sm4cbc.ivHex", "")
);
} catch (Exception e) {
log.error("9.2.10 发票获取接口请求参数 SM4CBC 加密出错", e);
throw new IllegalArgumentException("发票获取请求参数加密失败");
}
HashMap<String, Object> bodyMap = new HashMap<>();
bodyMap.put("Address4", supplier.getSupplierApiUrl() + "/supplierOpenApi/pointOrder/queryInvoicesInfo");
bodyMap.put("BussDealMd", "P");
bodyMap.put("SroNo", supplier.getSroNo());
bodyMap.put("RsrvFld1", supplier.getClientId());
bodyMap.put("AplParmObjct", encrypt);
String response = HttpUtil.createPost(clientBAB7ServerUrl)
.contentType("application/json;charset=UTF-8")
.body(JSONUtil.toJsonStr(bodyMap))
.execute()
.body();
if (StrUtil.isBlank(response)) {
throw new IllegalArgumentException("没有查询到发票信息");
}
JSONObject responseJson = JSONUtil.parseObj(response);
if (responseJson.getInt("resultCode", -1) != 0) {
throw new IllegalArgumentException(StrUtil.blankToDefault(responseJson.getStr("message"), "获取发票信息失败"));
}
JSONObject invoiceInfo = responseJson.getJSONObject("getInvoiceInfo");
if (invoiceInfo == null) {
throw new IllegalArgumentException("没有查询到发票信息");
}
return JSONUtil.toBean(invoiceInfo, GetInvoiceInfoDTO.class);
}
}
@@ -238,21 +238,21 @@ public class PointsMallReconciliationServiceImpl extends BaseServiceImpl<PointsM
cnd.and("r.supplierId", "=", param.getSupplierId());
}
if (StrUtil.isNotBlank(param.getOrderId())) {
cnd.and("r.orderId", "like", "%" + param.getOrderId() + "%");
cnd.and("r.orderId", "=", param.getOrderId());
}
if (StrUtil.isNotBlank(param.getUserId())) {
cnd.and("r.userId", "like", "%" + param.getUserId() + "%");
cnd.and("r.userId", "=", param.getUserId());
}
if (param.getDiffType() != null) {
cnd.and("r.diffType", "=", param.getDiffType());
}
if (StrUtil.isNotBlank(param.getBatchNo())) {
cnd.and("r.batchNo", "like", "%" + param.getBatchNo() + "%");
cnd.and("r.batchNo", "=", param.getBatchNo());
}
if (param.getNoticeStatus() != null) {
cnd.and("r.noticeStatus", "=", param.getNoticeStatus());
}
cnd.desc("r.createdAt");
cnd.desc("r.batchNo").desc("r.createdAt");
Sql sql = Sqls.create("select r.*, s.supplierName from points_mall_reconciliation_record r left join points_mall_supplier s on r.supplierId = s.supplierId and s.delFlag = 0 $condition");
sql.setCondition(cnd);
return listPageMap(param.getPageNumber(), param.getPageSize(), sql);
@@ -264,7 +264,8 @@ public class PointsMallReconciliationServiceImpl extends BaseServiceImpl<PointsM
}
private Cnd orderCnd(PointsMallReconciliationOrderPageParam param, String alias) {
Cnd cnd = Cnd.where(field(alias, "delFlag"), "=", false);
Cnd cnd = Cnd.where(field(alias, "delFlag"), "=", false)
.and(field(alias, "orderState"), "=", 5);
if (StrUtil.isNotBlank(param.getSupplierId())) {
cnd.and(field(alias, "supplierId"), "=", param.getSupplierId());
}
@@ -335,6 +336,9 @@ public class PointsMallReconciliationServiceImpl extends BaseServiceImpl<PointsM
if (StrUtil.isBlank(param.getStartDate()) || StrUtil.isBlank(param.getEndDate())) {
throw new IllegalArgumentException("对账日期不能为空");
}
if (param.getReconciliationType() == 2 && StrUtil.isBlank(param.getOrderId())) {
throw new IllegalArgumentException("订单号不能为空");
}
}
private void subOrderReconciliationUpdate(List<PointsMallReconciliationRecord> reconciliationList, Integer reconciliationStatus) {
@@ -30,21 +30,21 @@ public class PointsMallReconciliationRecordServiceImpl extends BaseServiceImpl<P
cnd.and("r.supplierId", "=", param.getSupplierId());
}
if (StrUtil.isNotBlank(param.getOrderId())) {
cnd.and("r.orderId", "like", "%" + param.getOrderId() + "%");
cnd.and("r.orderId", "=", param.getOrderId());
}
if (StrUtil.isNotBlank(param.getUserId())) {
cnd.and("r.userId", "like", "%" + param.getUserId() + "%");
cnd.and("r.userId", "=", param.getUserId());
}
if (param.getDiffType() != null) {
cnd.and("r.diffType", "=", param.getDiffType());
}
if (StrUtil.isNotBlank(param.getBatchNo())) {
cnd.and("r.batchNo", "like", "%" + param.getBatchNo() + "%");
cnd.and("r.batchNo", "=", param.getBatchNo());
}
if (param.getNoticeStatus() != null) {
cnd.and("r.noticeStatus", "=", param.getNoticeStatus());
}
cnd.desc("r.createdAt");
cnd.desc("r.batchNo").desc("r.createdAt");
Sql sql = Sqls.create("select r.*, s.supplierName from points_mall_reconciliation_record r left join points_mall_supplier s on r.supplierId = s.supplierId and s.delFlag = 0 $condition");
sql.setCondition(cnd);
return listPageMap(param.getPageNumber(), param.getPageSize(), sql);
@@ -1,23 +1,36 @@
package com.budwk.app.zhgh.pointsmall.supplier.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.budwk.app.base.exception.BaseException;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.sys.models.Sys_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
import com.budwk.app.zhgh.pointsmall.supplier.param.PointsMallSupplierPageParam;
import com.budwk.app.zhgh.pointsmall.supplier.service.PointsMallSupplierService;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@IocBean(args = {"refer:dao"})
public class PointsMallSupplierServiceImpl extends BaseServiceImpl<PointsMallSupplier> implements PointsMallSupplierService {
@Inject
private RedisService redisService;
public PointsMallSupplierServiceImpl(Dao dao) {
super(dao);
}
@@ -52,7 +65,32 @@ public class PointsMallSupplierServiceImpl extends BaseServiceImpl<PointsMallSup
cnd.and("mallType", "=", mallType);
}
cnd.asc("sortCode");
return dao().query(PointsMallSupplier.class, cnd);
List<PointsMallSupplier> list = dao().query(PointsMallSupplier.class, cnd);
if (Objects.equals(1, mallType)) {
Sys_user user = dao().fetch(Sys_user.class, SecurityUtil.getUserId());
if (user == null || StrUtil.isBlank(user.getVirtualId())) {
throw new BaseException("用户不存在");
}
for (PointsMallSupplier supplier : list) {
supplier.setSupplierUrl(getSupplierIndexUrl(user, supplier));
}
}
return list;
}
private String getSupplierIndexUrl(Sys_user user, PointsMallSupplier supplier) {
String supplierUrl = supplier.getSupplierUrl();
if (StrUtil.isBlank(supplierUrl) || !Objects.equals(1, supplier.getMallType())) {
return supplierUrl;
}
Map<String, String> params = new HashMap<>();
params.put("userId", user.getVirtualId());
if ("10101013".equals(supplier.getSupplierId())) {
params.put("orgId", user.getVirtualOrgId());
}
String keyword = IdUtil.fastSimpleUUID();
redisService.setex("supplier-session:" + keyword, 300, JSONUtil.toJsonStr(params));
return supplierUrl.concat(keyword);
}
@Override
@@ -86,7 +86,7 @@ layout("/layouts/platform.html"){
<el-input clearable placeholder="请输入发票抬头" v-model="applyForm.invoiceTitle"></el-input>
</el-form-item>
<el-form-item label="纳税人识别号" required>
<el-input clearable placeholder="请输入纳税人识别号" v-model="applyForm.invoiceCode"></el-input>
<el-input clearable placeholder="请输入纳税人识别号" v-model="applyForm.taxIdNumber"></el-input>
</el-form-item>
<el-form-item label="发票地址" required>
<el-input clearable placeholder="请输入发票地址" v-model="applyForm.invoiceAddress"></el-input>
@@ -275,7 +275,7 @@ layout("/layouts/platform.html"){
endDate: null,
invoiceDate: null,
invoiceTitle: null,
invoiceCode: null,
taxIdNumber: null,
invoiceAddress: null,
invoiceContact: null,
invoiceType: 10,
@@ -3,44 +3,74 @@ layout("/layouts/platform.html"){
#-->
<div id="app" v-cloak>
<el-card shadow="never">
<search @search="doSearch">
<search-item label="供应商">
<el-select clearable filterable placeholder="请选择供应商" style="width: 100%" v-model="pageForm.supplierId">
<el-option :key="item.supplierId" :label="item.supplierName" :value="item.supplierId" v-for="item in supplierList"></el-option>
</el-select>
</search-item>
<search-item label="订单ID">
<el-input clearable placeholder="多个订单ID用英文逗号分隔" v-model="pageForm.orderId"></el-input>
</search-item>
<search-item label="用户ID">
<el-input clearable placeholder="请输入用户ID" v-model="pageForm.userId"></el-input>
</search-item>
<search-item label="起始日期">
<el-date-picker clearable placeholder="开始日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="pageForm.startDate"></el-date-picker>
</search-item>
<search-item label="结束日期">
<el-date-picker clearable placeholder="结束日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="pageForm.endDate"></el-date-picker>
</search-item>
<search-item label="对账状态">
<el-select clearable placeholder="请选择对账状态" style="width: 100%" v-model="pageForm.reconciliationStatus">
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in reconciliationStatusOptions"></el-option>
</el-select>
</search-item>
<search-item label="发票状态">
<el-select clearable placeholder="请选择发票状态" style="width: 100%" v-model="pageForm.invoiceStatus">
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in invoiceStatusOptions"></el-option>
</el-select>
</search-item>
</search>
<el-card :body-style="{ paddingBottom: '2px' }" shadow="never">
<el-form label-width="96px" @submit.native.prevent>
<el-row :gutter="8">
<el-col :lg="4" :md="12" :xs="24">
<el-form-item label="供应商">
<el-select clearable filterable placeholder="请选择供应商" style="width: 100%" v-model="pageForm.supplierId">
<el-option :key="item.supplierId" :label="item.supplierName" :value="item.supplierId" v-for="item in supplierList"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :lg="4" :md="12" :xs="24">
<el-form-item label="起始日期">
<el-date-picker clearable placeholder="开始日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="pageForm.startDate"></el-date-picker>
</el-form-item>
</el-col>
<el-col :lg="4" :md="12" :xs="24">
<el-form-item label="结束日期">
<el-date-picker clearable placeholder="结束日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="pageForm.endDate"></el-date-picker>
</el-form-item>
</el-col>
<el-col :lg="4" :md="12" :xs="24">
<el-form-item label="对账类型">
<el-select clearable placeholder="请选择对账类型" style="width: 100%" v-model="pageForm.reconciliationType">
<el-option label="正常订单对账" :value="1"></el-option>
<el-option label="历史异常订单对账" :value="2"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :lg="4" :md="12" :xs="24">
<el-form-item label="发票状态">
<el-select clearable placeholder="请选择发票状态" style="width: 100%" v-model="pageForm.invoiceStatus">
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in invoiceStatusOptions"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :lg="4" :md="12" :xs="24">
<el-form-item label="对账状态">
<el-select clearable placeholder="请选择对账状态" style="width: 100%" v-model="pageForm.reconciliationStatus">
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in reconciliationStatusOptions"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :lg="6" :md="24" :xs="24">
<el-form-item label="订单ID">
<el-input clearable placeholder="多个订单ID用英文逗号分隔" v-model="pageForm.orderId"></el-input>
</el-form-item>
</el-col>
<el-col :lg="12" :md="24" :xs="24">
<el-form-item label-width="16px">
<el-button @click="doSearch" native-type="button" type="primary">查询</el-button>
<el-button @click="resetSearch" native-type="button">重置</el-button>
<el-button @click="openReconcileDialog" native-type="button" type="success">对账</el-button>
<el-button
v-if="pageForm.reconciliationStatus === 1 && hasSearched && pageForm.invoiceStatus === 0"
@click="openApplyDialog"
native-type="button"
type="warning"
>开票申请</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<el-card class="mt10" shadow="never">
<table-tool label="对账订单列表">
<el-button @click="openReconcileDialog" size="mini" type="success">对账</el-button>
<el-button @click="openRecordDialog" size="mini" type="primary">对账记录</el-button>
</table-tool>
<el-table :data="tableData" border class="vi-table" size="small" style="width: 100%" v-loading="tableLoading">
<table-tool label="对账订单列表"></table-tool>
<el-table ref="tableRef" :data="tableData" @selection-change="selectionChange" border class="vi-table" size="small" style="width: 100%" v-loading="tableLoading">
<el-table-column align="center" type="selection" width="50"></el-table-column>
<el-table-column :index="indexMethod" align="center" label="序号" type="index" width="70"></el-table-column>
<el-table-column align="center" label="订单ID" min-width="170" prop="orderId" show-overflow-tooltip></el-table-column>
<el-table-column align="center" label="供应商" min-width="150" prop="supplierName" show-overflow-tooltip></el-table-column>
@@ -87,39 +117,43 @@ layout("/layouts/platform.html"){
</el-card>
<el-dialog :close-on-click-modal="false" title="确认对账" :visible.sync="reconcileDialogVisible" width="480px">
<el-form label-width="100px" size="small">
<el-form-item label="供应商">
<el-select clearable filterable placeholder="请选择供应商" style="width: 100%" v-model="reconcileForm.supplierId">
<el-option :key="item.supplierId" :label="item.supplierName" :value="item.supplierId" v-for="item in supplierList"></el-option>
</el-select>
</el-form-item>
<el-form-item label="对账类型">
<el-select placeholder="请选择对账类型" style="width: 100%" v-model="reconcileForm.reconciliationType">
<el-option label="正常订单对账" :value="1"></el-option>
<el-option label="历史异常订单对账" :value="2"></el-option>
</el-select>
</el-form-item>
<el-form-item label="起始日期">
<el-date-picker placeholder="开始日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="reconcileForm.startDate"></el-date-picker>
</el-form-item>
<el-form-item label="结束日期">
<el-date-picker placeholder="结束日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="reconcileForm.endDate"></el-date-picker>
</el-form-item>
<el-form-item label="订单ID">
<el-input clearable placeholder="多个订单ID用英文逗号分隔" v-model="reconcileForm.orderId"></el-input>
</el-form-item>
<el-form-item label="积分合计">
<span>{{ reconcilePointsTotal }}</span>
</el-form-item>
</el-form>
<el-alert :closable="false" show-icon title="确认后订单将更新为已对账或对账异常,并生成对账记录。" type="warning"></el-alert>
<el-descriptions :column="1" border size="small">
<el-descriptions-item label="本次对账金额">{{ reconcilePointsTotal }}</el-descriptions-item>
</el-descriptions>
<el-alert :closable="false" show-icon style="margin-top: 16px" title="请记录当前对账积分金额,确认对账后该数值将不再展示。" type="warning"></el-alert>
<span slot="footer">
<el-button @click="reconcileDialogVisible = false">取消</el-button>
<el-button @click="loadPointsTotal" :loading="pointsTotalLoading">计算金额</el-button>
<el-button @click="executeReconciliation" :loading="executeLoading" type="primary">确认对账</el-button>
</span>
</el-dialog>
<el-dialog :close-on-click-modal="false" title="开票申请" :visible.sync="applyDialogVisible" top="5vh" width="720px">
<el-form ref="applyFormRef" :model="applyForm" :rules="applyRules" label-width="120px" size="small">
<el-form-item label="开票日期" prop="invoiceDate">
<el-date-picker placeholder="请选择开票日期" style="width: 100%" type="date" value-format="yyyy-MM-dd" v-model="applyForm.invoiceDate"></el-date-picker>
</el-form-item>
<el-form-item label="发票抬头" prop="invoiceTitle" required>
<el-input clearable placeholder="请输入发票抬头" v-model="applyForm.invoiceTitle"></el-input>
</el-form-item>
<el-form-item label="纳税人识别号" prop="taxIdNumber" required>
<el-input clearable placeholder="请输入纳税人识别号" v-model="applyForm.taxIdNumber"></el-input>
</el-form-item>
<el-form-item label="开户地址" prop="invoiceAddress" required>
<el-input clearable placeholder="请输入发票地址" v-model="applyForm.invoiceAddress"></el-input>
</el-form-item>
<el-form-item label="联系电话" prop="invoiceContact" required>
<el-input clearable maxlength="11" placeholder="请输入联系电话" v-model="applyForm.invoiceContact"></el-input>
</el-form-item>
<el-form-item label="发票类型" prop="invoiceType" required>
<dict-select clearable code="invoice_type" placeholder="请选择发票类型" style="width: 100%" v-model="applyForm.invoiceType"></dict-select>
</el-form-item>
</el-form>
<span slot="footer">
<el-button @click="applyDialogVisible = false">取消</el-button>
<el-button @click="submitApply" :loading="applyLoading" type="primary">确认开票</el-button>
</span>
</el-dialog>
<el-dialog :close-on-click-modal="false" title="对账记录" :visible.sync="recordDialogVisible" top="5vh" width="90%">
<el-form :inline="true" size="small" @submit.native.prevent>
<el-form-item label="供应商">
@@ -209,6 +243,8 @@ layout("/layouts/platform.html"){
supplierList: [],
tableData: [],
tableLoading: false,
selections: [],
hasSearched: false,
pageForm: {
pageNumber: 1,
pageSize: 10,
@@ -218,6 +254,7 @@ layout("/layouts/platform.html"){
userId: null,
startDate: null,
endDate: null,
reconciliationType: null,
reconciliationStatus: null,
invoiceStatus: null
},
@@ -232,6 +269,36 @@ layout("/layouts/platform.html"){
startDate: null,
endDate: null
},
applyDialogVisible: false,
applyLoading: false,
applyForm: {
invoiceDate: null,
invoiceTitle: null,
taxIdNumber: null,
invoiceAddress: null,
invoiceContact: null,
invoiceType: null
},
applyRules: {
invoiceDate: [{ required: true, message: "请选择开票日期", trigger: "change" }],
invoiceTitle: [{ required: true, message: "请输入发票抬头", trigger: "blur" }],
taxIdNumber: [{ required: true, message: "请输入纳税人识别号", trigger: "blur" }],
invoiceAddress: [{ required: true, message: "请输入开户地址", trigger: "blur" }],
invoiceContact: [
{ required: true, message: "请输入联系电话", trigger: "blur" },
{
validator(rule, value, callback) {
if (value && !/^1[3-9]\d{9}$/.test(value)) {
callback(new Error("请输入正确的手机号码"))
} else {
callback()
}
},
trigger: "blur"
}
],
invoiceType: [{ required: true, message: "请选择发票类型", trigger: "change" }]
},
recordDialogVisible: false,
recordLoading: false,
recordList: [],
@@ -279,9 +346,32 @@ layout("/layouts/platform.html"){
return index + 1 + (this.recordForm.pageNumber - 1) * this.recordForm.pageSize
},
doSearch() {
this.hasSearched = true
this.selections = []
this.pageForm.pageNumber = 1
this.pageData()
},
resetSearch() {
this.pageForm = {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
supplierId: null,
orderId: null,
userId: null,
startDate: null,
endDate: null,
reconciliationType: null,
reconciliationStatus: null,
invoiceStatus: null
}
this.hasSearched = false
this.selections = []
this.pageData()
},
selectionChange(rows) {
this.selections = rows || []
},
async pageData() {
this.tableLoading = true
const resp = await this.$axios.post(loc() + "/pageData", this.pageForm)
@@ -308,48 +398,114 @@ layout("/layouts/platform.html"){
this.supplierList = resp.data || []
}
},
openReconcileDialog() {
async openReconcileDialog() {
this.reconcileForm = {
supplierId: this.pageForm.supplierId,
reconciliationType: this.pageForm.reconciliationStatus === 2 ? 2 : 1,
reconciliationType: this.pageForm.reconciliationType,
orderId: this.pageForm.orderId,
startDate: this.pageForm.startDate,
endDate: this.pageForm.endDate
}
this.reconcilePointsTotal = 0
this.reconcileDialogVisible = true
this.loadPointsTotal()
},
async loadPointsTotal() {
if (!this.reconcileForm.supplierId || !this.reconcileForm.startDate || !this.reconcileForm.endDate || !this.reconcileForm.reconciliationType) {
this.notifyWarning("请先选择供应商、对账类型和对账日期")
if (!this.reconciliationParamsComplete()) {
this.notifyWarning(this.reconcileForm.reconciliationType === 2 ? "请选择供应商、对账类型、对账日期并填写订单ID" : "请选择供应商、对账类型和对账日期")
return
}
if (await this.loadPointsTotal()) {
this.reconcileDialogVisible = true
}
},
reconciliationParamsComplete() {
if (!this.reconcileForm.supplierId || !this.reconcileForm.reconciliationType) {
return false
}
if (!this.reconcileForm.startDate || !this.reconcileForm.endDate) {
return false
}
return this.reconcileForm.reconciliationType !== 2 || !!this.reconcileForm.orderId
},
async loadPointsTotal() {
if (!this.reconciliationParamsComplete()) {
return false
}
this.pointsTotalLoading = true
const resp = await this.$axios.post(loc() + "/pointsTotal", this.reconcileForm)
this.pointsTotalLoading = false
if (resp.code === 0) {
this.reconcilePointsTotal = resp.data || 0
} else {
try {
const resp = await this.$axios.post(loc() + "/pointsTotal", this.reconcileForm)
if (resp.code === 0) {
this.reconcilePointsTotal = resp.data || 0
return true
}
this.notifyWarning(resp.msg)
return false
} finally {
this.pointsTotalLoading = false
}
},
async executeReconciliation() {
if (!this.reconcileForm.supplierId || !this.reconcileForm.startDate || !this.reconcileForm.endDate || !this.reconcileForm.reconciliationType) {
this.notifyWarning("请先选择供应商、对账类型和对账日期")
if (!this.reconciliationParamsComplete()) {
this.notifyWarning(this.reconcileForm.reconciliationType === 2 ? "请先选择供应商并填写订单ID" : "请先选择供应商、对账类型和对账日期")
return
}
this.executeLoading = true
const resp = await this.$axios.post(loc() + "/execute", this.reconcileForm)
this.executeLoading = false
if (resp.code === 0) {
this.notifySuccess(resp.data || "对账完成")
this.reconcileDialogVisible = false
this.pageData()
} else {
this.notifyWarning(resp.msg)
try {
const resp = await this.$axios.post(loc() + "/execute", this.reconcileForm)
if (resp.code === 0) {
this.notifySuccess(resp.data || "对账完成")
this.reconcileDialogVisible = false
this.pageData()
} else {
this.notifyWarning(resp.msg)
}
} finally {
this.executeLoading = false
}
},
openApplyDialog() {
if (!this.pageForm.supplierId || !this.pageForm.startDate || !this.pageForm.endDate) {
return
}
if (!this.selections.length) {
this.notifyWarning("请先勾选需要开票的订单")
return
}
this.applyForm = {
invoiceDate: null,
invoiceTitle: null,
taxIdNumber: null,
invoiceAddress: null,
invoiceContact: null,
invoiceType: null
}
this.applyDialogVisible = true
},
submitApply() {
this.$refs.applyFormRef.validate(async (valid) => {
if (!valid) {
return
}
this.applyLoading = true
try {
const params = Object.assign({}, this.applyForm, {
supplierId: this.pageForm.supplierId,
startDate: this.pageForm.startDate,
endDate: this.pageForm.endDate,
orderIds: this.selections.map((item) => item.orderId).join(",")
})
const resp = await this.$axios.post("/platform/zhgh/points-mall/invoice/applyInvoice", params)
if (resp.code === 0) {
this.notifySuccess(resp.data || "开票申请成功")
this.applyDialogVisible = false
this.selections = []
this.$refs.tableRef.clearSelection()
this.pageData()
} else {
this.notifyWarning(resp.msg)
}
} finally {
this.applyLoading = false
}
})
},
openRecordDialog() {
this.recordDialogVisible = true
this.recordForm.supplierId = this.pageForm.supplierId
@@ -146,36 +146,12 @@ layout("/layouts/platform_h5.html"){
this.userPoints = resp.data || 0
}
},
async openSupplier(item) {
openSupplier(item) {
if (!item.supplierUrl) {
this.$toast("暂无跳转地址")
return
}
const virtualId = this.$store && this.$store.state.user ? this.$store.state.user.virtualId : ""
if (!virtualId) {
this.$toast("获取用户信息失败,请重新登录后再试")
return
}
window.location.href = this.withSupplierQuery(item.supplierUrl, {
userId: virtualId
})
},
withSupplierQuery(url, params) {
const query = Object.keys(params)
.filter((key) => params[key] !== undefined && params[key] !== null && params[key] !== "")
.map((key) => encodeURIComponent(key) + "=" + encodeURIComponent(params[key]))
.join("&")
if (!query) {
return url
}
const hashIndex = url.indexOf("#")
if (hashIndex > -1) {
const base = url.slice(0, hashIndex)
const hash = url.slice(hashIndex)
const joiner = hash.indexOf("?") > -1 ? "&" : "?"
return base + hash + joiner + query
}
return url + (url.indexOf("?") > -1 ? "&" : "?") + query
window.location.href = item.supplierUrl
},
onImgError(e) {
e.target.src = this.defaultLogo