feat: 积分商城-补充

This commit is contained in:
2026-07-29 10:11:25 +08:00
parent 0eefc705a1
commit 51a951d863
22 changed files with 923 additions and 93 deletions
@@ -1,7 +1,9 @@
package com.budwk.app.zhgh.pointsmall.h5.index; package com.budwk.app.zhgh.pointsmall.h5.index;
import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import com.budwk.app.base.result.Result; import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.pointsmall.points.service.PointsMallUserPointsService;
import com.budwk.app.zhgh.pointsmall.supplier.service.PointsMallSupplierService; import com.budwk.app.zhgh.pointsmall.supplier.service.PointsMallSupplierService;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
@@ -13,10 +15,12 @@ import org.nutz.mvc.annotation.Param;
@Ok("json:full") @Ok("json:full")
@At("/platform/h5/points-mall") @At("/platform/h5/points-mall")
public class PointsMallH5IndexController { public class PointsMallH5IndexController {
@Inject @Inject
private PointsMallSupplierService pointsMallSupplierService; private PointsMallSupplierService pointsMallSupplierService;
@Inject
private PointsMallUserPointsService pointsMallUserPointsService;
@At("") @At("")
@Ok("beetl:/platform/zhghh5/points-mall/index.html") @Ok("beetl:/platform/zhghh5/points-mall/index.html")
@SaCheckPermission("h5.points.mall") @SaCheckPermission("h5.points.mall")
@@ -28,4 +32,18 @@ public class PointsMallH5IndexController {
public Result supplierList(@Param("mallType") Integer mallType) { public Result supplierList(@Param("mallType") Integer mallType) {
return Result.success(pointsMallSupplierService.listByMallType(mallType)); return Result.success(pointsMallSupplierService.listByMallType(mallType));
} }
@At("/me/points")
@SaCheckPermission("h5.points.mall")
public Result points() {
return Result.success(pointsMallUserPointsService.availablePoints(currentUserId()));
}
private String currentUserId() {
try {
return StpUtil.getLoginIdAsString();
} catch (Exception e) {
return "";
}
}
} }
@@ -0,0 +1,11 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MallTokenRequired {
}
@@ -1,24 +1,29 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.controller; package com.budwk.app.zhgh.pointsmall.mallbridge.controller;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.pointsmall.mallbridge.annotation.MallTokenRequired;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.*; import com.budwk.app.zhgh.pointsmall.mallbridge.dto.*;
import com.budwk.app.zhgh.pointsmall.mallbridge.interceptor.MallTokenInterceptor;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundPointsResult; import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundPointsResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult; import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult; import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallPictureOutboundResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.service.PointsMallBridgeService; import com.budwk.app.zhgh.pointsmall.mallbridge.service.PointsMallBridgeService;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json; import org.nutz.mvc.adaptor.JsonAdaptor;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.By;
import org.nutz.mvc.annotation.Filters;
import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.annotation.POST; import org.nutz.mvc.annotation.POST;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
@IocBean @IocBean
@Ok("json:full") @Ok("json:full")
@At("/open") @At("/open")
@AdaptBy(type = JsonAdaptor.class)
public class PointsMallBridgeController { public class PointsMallBridgeController {
@Inject @Inject
@@ -26,9 +31,9 @@ public class PointsMallBridgeController {
@POST @POST
@At("/connect/token") @At("/connect/token")
public MallInboundResult getToken(HttpServletRequest request) { public MallInboundResult getToken(@Param("..") MallTokenDTO dto) {
try { try {
return pointsMallBridgeService.getToken(readBody(request, MallTokenDTO.class)); return pointsMallBridgeService.getToken(dto);
} catch (Exception e) { } catch (Exception e) {
return MallInboundResult.fail(401, e.getMessage()); return MallInboundResult.fail(401, e.getMessage());
} }
@@ -36,9 +41,9 @@ public class PointsMallBridgeController {
@POST @POST
@At("/connect/refreshToken") @At("/connect/refreshToken")
public MallInboundResult refreshToken(HttpServletRequest request) { public MallInboundResult refreshToken(@Param("..") MallTokenRefreshDTO dto) {
try { try {
return pointsMallBridgeService.refreshToken(readBody(request, MallTokenRefreshDTO.class)); return pointsMallBridgeService.refreshToken(dto);
} catch (Exception e) { } catch (Exception e) {
return MallInboundResult.fail(401, e.getMessage()); return MallInboundResult.fail(401, e.getMessage());
} }
@@ -46,9 +51,11 @@ public class PointsMallBridgeController {
@POST @POST
@At("/pointOrder/queryPoints") @At("/pointOrder/queryPoints")
public MallInboundPointsResult queryPoints(HttpServletRequest request) { @MallTokenRequired
@Filters(@By(type = MallTokenInterceptor.class))
public MallInboundPointsResult queryPoints(@Param("..") MallPointQueryDTO dto) {
try { try {
return pointsMallBridgeService.queryPoints(readBody(request, MallPointQueryDTO.class)); return pointsMallBridgeService.queryPoints(dto);
} catch (Exception e) { } catch (Exception e) {
return MallInboundPointsResult.fail(401, e.getMessage()); return MallInboundPointsResult.fail(401, e.getMessage());
} }
@@ -56,38 +63,88 @@ public class PointsMallBridgeController {
@POST @POST
@At("/pointOrder/pendingOrderInfo") @At("/pointOrder/pendingOrderInfo")
public MallInboundResult receivePending(HttpServletRequest request) { @MallTokenRequired
return inbound(() -> pointsMallBridgeService.receivePending(readBody(request, MallPendingOrderDTO.class))); @Filters(@By(type = MallTokenInterceptor.class))
public MallInboundResult receivePending(@Param("..") MallPendingOrderDTO dto) {
return inbound(() -> pointsMallBridgeService.receivePending(dto));
} }
@POST @POST
@At("/pointOrder/confirmPurchase") @At("/pointOrder/confirmPurchase")
public MallInboundResult confirmPurchase(HttpServletRequest request) { @MallTokenRequired
return inbound(() -> pointsMallBridgeService.confirmPurchase(readBody(request, MallPurchaseConfirmDTO.class))); @Filters(@By(type = MallTokenInterceptor.class))
public MallInboundResult confirmPurchase(@Param("..") MallPurchaseConfirmDTO dto) {
return inbound(() -> pointsMallBridgeService.confirmPurchase(dto));
} }
@POST @POST
@At("/pointOrder/purchaseResult") @At("/pointOrder/purchaseResult")
public MallInboundResult purchaseResult(HttpServletRequest request) { @MallTokenRequired
return inbound(() -> pointsMallBridgeService.purchaseResult(readBody(request, MallPurchaseResultDTO.class))); @Filters(@By(type = MallTokenInterceptor.class))
public MallInboundResult purchaseResult(@Param("..") MallPurchaseResultDTO dto) {
return inbound(() -> pointsMallBridgeService.purchaseResult(dto));
} }
@POST @POST
@At("/pointOrder/pushOrderInfoMsg") @At("/pointOrder/pushOrderInfoMsg")
public MallInboundResult receiveEvent(HttpServletRequest request) { @MallTokenRequired
return inbound(() -> pointsMallBridgeService.receiveEvent(readBody(request, MallOrderEventDTO.class))); @Filters(@By(type = MallTokenInterceptor.class))
public MallInboundResult receiveEvent(@Param("..") MallOrderEventDTO dto) {
return inbound(() -> pointsMallBridgeService.receiveEvent(dto));
} }
@POST @POST
@At("/pointOrder/queryOrderInfo") @At("/pointOrder/queryOrderInfo")
public MallOutboundResult queryOrderInfo(HttpServletRequest request) { public MallOutboundResult queryOrderInfo(@Param("..") MallOrderQueryDTO dto) {
try { try {
return pointsMallBridgeService.queryOrderInfo(readBody(request, MallOrderQueryDTO.class)); return pointsMallBridgeService.queryOrderInfo(dto);
} catch (Exception e) { } catch (Exception e) {
return MallOutboundResult.fail(401, e.getMessage()); return MallOutboundResult.fail(401, e.getMessage());
} }
} }
@POST
@At("/pointOrder/applyForInvoices")
public MallOutboundResult applyInvoice(@Param("..") MallInvoiceApplyDTO dto) {
try {
return pointsMallBridgeService.applyInvoice(dto);
} catch (Exception e) {
return MallOutboundResult.fail(401, e.getMessage());
}
}
@POST
@At("/pointOrder/queryInvoicesInfo")
public Result queryInvoicesInfo(@Param("..") QueryInvoiceInfoDTO dto) {
try {
return Result.success(pointsMallBridgeService.queryInvoicesInfo(dto));
} catch (Exception e) {
return Result.error(401, e.getMessage());
}
}
@POST
@At("/pointOrder/queryFileBase64Info")
public MallPictureOutboundResult queryFileBase64Info(@Param("..") PictureQueryDTO dto) {
try {
return pointsMallBridgeService.queryFileBase64Info(dto);
} catch (Exception e) {
return MallPictureOutboundResult.fail(401, e.getMessage());
}
}
@POST
@At("/pointOrder/unReconciledMsg")
public MallInboundResult unReconciledMsg(@Param("..") UnReconciledMsgNoticeDTO dto) {
return inbound(() -> pointsMallBridgeService.unReconciledMsg(dto));
}
@POST
@At("/pointOrder/payCompletion")
public MallInboundResult payCompletion(@Param("..") OrderPayFinishNoticeDTO dto) {
return inbound(() -> pointsMallBridgeService.payCompletion(dto));
}
private MallInboundResult inbound(InboundCall call) { private MallInboundResult inbound(InboundCall call) {
try { try {
return call.get(); return call.get();
@@ -96,17 +153,6 @@ public class PointsMallBridgeController {
} }
} }
private <T> T readBody(HttpServletRequest request, Class<T> type) throws IOException {
StringBuilder body = new StringBuilder();
try (BufferedReader reader = request.getReader()) {
String line;
while ((line = reader.readLine()) != null) {
body.append(line);
}
}
return Json.fromJson(type, body.toString());
}
private interface InboundCall { private interface InboundCall {
MallInboundResult get() throws Exception; MallInboundResult get() throws Exception;
} }
@@ -0,0 +1,14 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class FinalStatementDTO {
private String settlementId;
private String invoiceIds;
private String orderIds;
private String payDate;
private BigDecimal totalFee;
}
@@ -0,0 +1,15 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
import lombok.Data;
import java.util.List;
@Data
public class GetInvoiceInfoDTO {
private Integer bSuccess;
private String settlementId;
private String sucOrderIds;
private String failOrderIds;
private String failMsg;
private List<InvoiceInfoDTO> invoiceInfos;
}
@@ -0,0 +1,23 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
@Data
public class InvoiceInfoDTO {
private String invoiceId;
private String invoiceCode;
private LocalDate invoiceDate;
private BigDecimal invoiceNakeAmount;
private BigDecimal invoiceTaxRate;
private BigDecimal invoiceTaxAmount;
private BigDecimal invoiceAmount;
private Integer invoiceType;
private String url;
private String imageEncode;
private String fileType;
private String checkCode;
private String invoiceAddress;
}
@@ -0,0 +1,29 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class MallInvoiceApplyDTO {
private String supplierId;
private String token;
private String settlementId;
private String orderIds;
private Integer orderNum;
private BigDecimal orderTotalPrice;
private String invoiceDate;
private String invoiceTitle;
private String invoiceCode;
private String invoiceAddress;
private String invoiceContact;
private BigDecimal invoiceNakedPrice;
private BigDecimal invoiceTaxPrice;
private String invoiceType;
private String invoiceContent;
private String remark;
private String bankAccount;
private String registeredAddress;
private String bankName;
private Long timestamp;
}
@@ -7,6 +7,7 @@ public class MallTokenDTO {
private String supplierId; private String supplierId;
private String clientId; private String clientId;
private String clientSecret; private String clientSecret;
private String sendSha256;
private String code; private String code;
private String timestamp; private String timestamp;
} }
@@ -8,5 +8,6 @@ public class MallTokenRefreshDTO {
private String refreshToken; private String refreshToken;
private String clientId; private String clientId;
private String clientSecret; private String clientSecret;
private String sendSha256;
private String timestamp; private String timestamp;
} }
@@ -0,0 +1,14 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
import lombok.Data;
import java.util.List;
@Data
public class OrderPayFinishNoticeDTO {
private String supplierId;
private String token;
private String expReportNumber;
private List<FinalStatementDTO> expFinalInfos;
private Long timestamp;
}
@@ -0,0 +1,15 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
import lombok.Data;
import java.util.List;
@Data
public class PictureQueryDTO {
private String supplierId;
private String token;
private String queryType;
private String idNumber;
private List<String> fileIdList;
private Long timestamp;
}
@@ -0,0 +1,11 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
import lombok.Data;
@Data
public class QueryInvoiceInfoDTO {
private String supplierId;
private String token;
private String settlementId;
private Long timestamp;
}
@@ -0,0 +1,15 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.dto;
import lombok.Data;
@Data
public class UnReconciledMsgNoticeDTO {
private String uniqueSeqNo;
private String supplierId;
private String token;
private String orderIds;
private String unReconciledMsg;
private String unReconciledType;
private String startDate;
private String endDate;
}
@@ -0,0 +1,52 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.interceptor;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.zhgh.pointsmall.mallbridge.annotation.MallTokenRequired;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.models.PointsMallSupplierTokenStore;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.json.JsonFormat;
import org.nutz.mvc.ActionContext;
import org.nutz.mvc.ActionFilter;
import org.nutz.mvc.Mvcs;
import org.nutz.mvc.View;
import org.nutz.mvc.view.UTF8JsonView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
public class MallTokenInterceptor implements ActionFilter {
@Override
public View match(ActionContext actionContext) {
if (actionContext.getMethod() == null || !actionContext.getMethod().isAnnotationPresent(MallTokenRequired.class)) {
return null;
}
String accessToken = actionContext.getRequest().getHeader("token");
if (StrUtil.isBlank(accessToken)) {
return fail(401, "缺少accessToken参数");
}
Dao dao = Mvcs.getIoc().get(Dao.class);
PointsMallSupplierTokenStore tokenStore = dao.fetch(PointsMallSupplierTokenStore.class,
Cnd.where("accessToken", "=", accessToken).and("isValid", "=", true));
if (tokenStore == null || tokenStore.getAccessExpireTime() == null || tokenStore.getAccessExpireTime().before(new Date())) {
return fail(401, "无效的accessToken");
}
return null;
}
private View fail(int code, String message) {
return new View() {
@Override
public void render(HttpServletRequest req, HttpServletResponse resp, Object obj) throws Throwable {
resp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
new UTF8JsonView(JsonFormat.compact()).render(req, resp, MallInboundResult.fail(code, message));
}
};
}
}
@@ -11,6 +11,10 @@ public class MallOutboundResult {
private String message; private String message;
private List<OrderInfoDTO> orderInfo; private List<OrderInfoDTO> orderInfo;
public static MallOutboundResult success() {
return success(null);
}
public static MallOutboundResult success(List<OrderInfoDTO> orderInfo) { public static MallOutboundResult success(List<OrderInfoDTO> orderInfo) {
MallOutboundResult result = new MallOutboundResult(); MallOutboundResult result = new MallOutboundResult();
result.setResultCode(0); result.setResultCode(0);
@@ -0,0 +1,57 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.model;
import java.util.Map;
public class MallPictureOutboundResult {
private int resultCode;
private String message;
private String fileType;
private Map<String, String> imageEncodeMap;
public static MallPictureOutboundResult success(Map<String, String> imageEncodeMap) {
MallPictureOutboundResult result = new MallPictureOutboundResult();
result.resultCode = 0;
result.message = "成功";
result.imageEncodeMap = imageEncodeMap;
return result;
}
public static MallPictureOutboundResult fail(int code, String message) {
MallPictureOutboundResult result = new MallPictureOutboundResult();
result.resultCode = code;
result.message = message;
return result;
}
public int getResultCode() {
return resultCode;
}
public void setResultCode(int resultCode) {
this.resultCode = resultCode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getFileType() {
return fileType;
}
public void setFileType(String fileType) {
this.fileType = fileType;
}
public Map<String, String> getImageEncodeMap() {
return imageEncodeMap;
}
public void setImageEncodeMap(Map<String, String> imageEncodeMap) {
this.imageEncodeMap = imageEncodeMap;
}
}
@@ -5,6 +5,7 @@ import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundPointsResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult; import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundTokenResult; import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundTokenResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult; import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallPictureOutboundResult;
public interface PointsMallBridgeService { public interface PointsMallBridgeService {
MallInboundTokenResult getToken(MallTokenDTO dto); MallInboundTokenResult getToken(MallTokenDTO dto);
@@ -22,4 +23,14 @@ public interface PointsMallBridgeService {
MallInboundResult receiveEvent(MallOrderEventDTO dto); MallInboundResult receiveEvent(MallOrderEventDTO dto);
MallOutboundResult queryOrderInfo(MallOrderQueryDTO dto); MallOutboundResult queryOrderInfo(MallOrderQueryDTO dto);
MallOutboundResult applyInvoice(MallInvoiceApplyDTO dto);
GetInvoiceInfoDTO queryInvoicesInfo(QueryInvoiceInfoDTO dto);
MallPictureOutboundResult queryFileBase64Info(PictureQueryDTO dto);
MallInboundResult unReconciledMsg(UnReconciledMsgNoticeDTO dto);
MallInboundResult payCompletion(OrderPayFinishNoticeDTO dto);
} }
@@ -1,22 +1,44 @@
package com.budwk.app.zhgh.pointsmall.mallbridge.service.impl; package com.budwk.app.zhgh.pointsmall.mallbridge.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.convert.Convert; import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.*; 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.FinalStatementDTO;
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.MallInvoiceApplyDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderEventDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallOrderQueryDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallPendingOrderDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallPointQueryDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallPurchaseConfirmDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallPurchaseResultDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallTokenDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.MallTokenRefreshDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderInfoDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderPayFinishNoticeDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.OrderProInfoDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.PictureQueryDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.QueryInvoiceInfoDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.dto.UnReconciledMsgNoticeDTO;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundPointsResult; import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundPointsResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult; import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundTokenResult; import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallInboundTokenResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult; import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallOutboundResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.model.MallPictureOutboundResult;
import com.budwk.app.zhgh.pointsmall.mallbridge.models.PointsMallSupplierTokenStore; import com.budwk.app.zhgh.pointsmall.mallbridge.models.PointsMallSupplierTokenStore;
import com.budwk.app.zhgh.pointsmall.mallbridge.service.PointsMallBridgeService; import com.budwk.app.zhgh.pointsmall.mallbridge.service.PointsMallBridgeService;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderMain; import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderMain;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub; import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSubProduct; import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSubProduct;
import com.budwk.app.zhgh.pointsmall.points.service.PointsMallUserPointsService; import com.budwk.app.zhgh.pointsmall.points.service.PointsMallUserPointsService;
import com.budwk.app.zhgh.pointsmall.reconciliation.models.PointsMallReconciliationRecord;
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier; import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.dao.Sqls; import org.nutz.dao.Sqls;
@@ -28,7 +50,16 @@ import org.nutz.trans.Atom;
import org.nutz.trans.Trans; import org.nutz.trans.Trans;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.*; import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@IocBean(args = {"refer:dao"}) @IocBean(args = {"refer:dao"})
@@ -36,6 +67,16 @@ public class PointsMallBridgeServiceImpl implements PointsMallBridgeService {
private static final long ACCESS_EXPIRE_SECONDS = 3600; private static final long ACCESS_EXPIRE_SECONDS = 3600;
private static final long REFRESH_EXPIRE_SECONDS = 86400L * 7; private static final long REFRESH_EXPIRE_SECONDS = 86400L * 7;
private static final int ORDER_PENDING_PAY = 0;
private static final int ORDER_FINISH_PAY = 1;
private static final int ORDER_IN_PROGRESS = 2;
private static final int ORDER_CANCELLED = 3;
private static final int ORDER_RECEIVED = 4;
private static final int ORDER_COMPLETED = 5;
private static final int ORDER_EXCHANGE = 6;
private static final int ORDER_REFUNDED = 7;
private static final int ORDER_ABOLISH = 8;
private final Dao dao; private final Dao dao;
@Inject @Inject
@@ -47,18 +88,18 @@ public class PointsMallBridgeServiceImpl implements PointsMallBridgeService {
@Override @Override
public MallInboundTokenResult getToken(MallTokenDTO dto) { public MallInboundTokenResult getToken(MallTokenDTO dto) {
PointsMallSupplier supplier = checkedSupplier(dto.getSupplierId(), dto.getClientId(), dto.getClientSecret(), dto.getTimestamp()); PointsMallSupplier supplier = checkedSupplier(dto.getSupplierId(), dto.getClientId(), dto.getClientSecret(), dto.getSendSha256(), dto.getTimestamp());
invalidateOldToken(supplier.getSupplierId(), supplier.getClientId()); invalidateOldToken(supplier.getSupplierId(), supplier.getClientId());
return createToken(supplier); return createToken(supplier);
} }
@Override @Override
public MallInboundTokenResult refreshToken(MallTokenRefreshDTO dto) { public MallInboundTokenResult refreshToken(MallTokenRefreshDTO dto) {
PointsMallSupplier supplier = checkedSupplier(dto.getSupplierId(), dto.getClientId(), dto.getClientSecret(), dto.getTimestamp()); PointsMallSupplier supplier = checkedSupplier(dto.getSupplierId(), dto.getClientId(), dto.getClientSecret(), dto.getSendSha256(), dto.getTimestamp());
PointsMallSupplierTokenStore store = dao.fetch(PointsMallSupplierTokenStore.class, Cnd.where("supplierId", "=", supplier.getSupplierId()) PointsMallSupplierTokenStore store = dao.fetch(PointsMallSupplierTokenStore.class, Cnd.where("supplierId", "=", supplier.getSupplierId())
.and("refreshToken", "=", dto.getRefreshToken()).and("isValid", "=", true)); .and("refreshToken", "=", dto.getRefreshToken()).and("isValid", "=", true));
if (store == null || store.getRefreshExpireTime() == null || new Date().after(store.getRefreshExpireTime())) { if (store == null || store.getRefreshExpireTime() == null || new Date().after(store.getRefreshExpireTime())) {
throw new IllegalArgumentException("刷新令牌无效或已过期"); throw new IllegalArgumentException("刷新令牌已失效,请重新获取授权");
} }
invalidateOldToken(supplier.getSupplierId(), supplier.getClientId()); invalidateOldToken(supplier.getSupplierId(), supplier.getClientId());
return createToken(supplier); return createToken(supplier);
@@ -66,68 +107,73 @@ public class PointsMallBridgeServiceImpl implements PointsMallBridgeService {
@Override @Override
public MallInboundPointsResult queryPoints(MallPointQueryDTO dto) { public MallInboundPointsResult queryPoints(MallPointQueryDTO dto) {
validateToken(dto.getSupplierId(), dto.getToken());
return MallInboundPointsResult.success(pointsMallUserPointsService.availablePoints(dto.getUserId())); return MallInboundPointsResult.success(pointsMallUserPointsService.availablePoints(dto.getUserId()));
} }
@Override @Override
public MallInboundResult receivePending(MallPendingOrderDTO dto) { public MallInboundResult receivePending(MallPendingOrderDTO dto) {
validateToken(dto.getSupplierId(), dto.getToken());
if (dto.getOrderInfo() == null || StrUtil.isBlank(dto.getOrderInfo().getOrderId())) { if (dto.getOrderInfo() == null || StrUtil.isBlank(dto.getOrderInfo().getOrderId())) {
return MallInboundResult.fail(400, "订单信息不能为空"); return MallInboundResult.fail(400, "订单信息不能为空");
} }
if (dao.count(PointsMallOrderMain.class, Cnd.where("orderId", "=", dto.getOrderInfo().getOrderId()).and("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false)) > 0) { if (dao.count(PointsMallOrderMain.class, Cnd.where("orderId", "=", dto.getOrderInfo().getOrderId())
.and("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false)) > 0) {
return MallInboundResult.fail(-1, "订单已存在"); return MallInboundResult.fail(-1, "订单已存在");
} }
Trans.exec((Atom) () -> dao.insert(toMain(dto.getSupplierId(), dto.getUserId(), dto.getOrderInfo(), 0))); Trans.exec((Atom) () -> dao.insert(toMain(dto.getSupplierId(), dto.getUserId(), dto.getOrderInfo(), ORDER_PENDING_PAY)));
return MallInboundResult.success(); return MallInboundResult.success();
} }
@Override @Override
public MallInboundResult confirmPurchase(MallPurchaseConfirmDTO dto) { public MallInboundResult confirmPurchase(MallPurchaseConfirmDTO dto) {
validateToken(dto.getSupplierId(), dto.getToken());
return updateMainOrderPay(dto.getSupplierId(), dto.getOrderId(), 1, dto.getTotalPrice(), dto.getWPayOrAPay(), dto.getPointsPrice()); return updateMainOrderPay(dto.getSupplierId(), dto.getOrderId(), 1, dto.getTotalPrice(), dto.getWPayOrAPay(), dto.getPointsPrice());
} }
@Override @Override
public MallInboundResult purchaseResult(MallPurchaseResultDTO dto) { public MallInboundResult purchaseResult(MallPurchaseResultDTO dto) {
validateToken(dto.getSupplierId(), dto.getToken()); int cashPaid = Boolean.TRUE.equals(dto.getPurchaseResult()) ? 1 : 0;
int state = Boolean.TRUE.equals(dto.getPurchaseResult()) ? 1 : 0; return updateMainOrderPay(dto.getSupplierId(), dto.getOrderId(), cashPaid, dto.getTotalPrice(), dto.getWPayOrAPay(), dto.getPointsPrice());
return updateMainOrderPay(dto.getSupplierId(), dto.getOrderId(), state, dto.getTotalPrice(), dto.getWPayOrAPay(), dto.getPointsPrice());
} }
@Override @Override
public MallInboundResult receiveEvent(MallOrderEventDTO dto) { public MallInboundResult receiveEvent(MallOrderEventDTO dto) {
validateToken(dto.getSupplierId(), dto.getToken());
Integer type = dto.getOrderType(); Integer type = dto.getOrderType();
if (type == null) { if (type == null) {
return MallInboundResult.fail(400, "订单事件类型不能为空"); return MallInboundResult.fail(400, "订单事件类型不能为空");
} }
if (type == 1) {
return cancelMainOrder(dto, false);
}
if (type == 2) { if (type == 2) {
return splitSubOrder(dto); return splitSubOrder(dto);
} }
if (type == 3) { if (type == 3) {
return updateSubState(dto, 3); return updateSubState(dto, ORDER_CANCELLED);
} }
if (type == 4) { if (type == 4) {
return updateSubState(dto, 4); return updateSubState(dto, ORDER_REFUNDED);
} }
if (type == 5) { if (type == 5) {
return updateSubState(dto, 5); return updateSubState(dto, ORDER_EXCHANGE);
} }
if (type == 6) { if (type == 6) {
return updateSubState(dto, 6); return updateSubState(dto, ORDER_COMPLETED);
} }
if (type == 7) { if (type == 7) {
return updateSubState(dto, 7); return cancelMainOrder(dto, true);
}
if (type == 8) {
return updateSubState(dto, ORDER_ABOLISH);
}
if (type == 11) {
return markInvoiceNotice(dto);
} }
return MallInboundResult.success(); return MallInboundResult.success();
} }
@Override @Override
public MallOutboundResult queryOrderInfo(MallOrderQueryDTO dto) { public MallOutboundResult queryOrderInfo(MallOrderQueryDTO dto) {
validateToken(dto.getSupplierId(), dto.getToken()); String table = Integer.valueOf(2).equals(dto.getOrderType()) ? "points_mall_order_sub" : "points_mall_order_main";
Sql sql = Sqls.create("select * from points_mall_order_main where supplierId=@supplierId and orderId=@orderId and delFlag=0"); Sql sql = Sqls.create("select * from " + table + " where supplierId=@supplierId and orderId=@orderId and delFlag=0");
sql.params().set("supplierId", dto.getSupplierId()); sql.params().set("supplierId", dto.getSupplierId());
sql.params().set("orderId", dto.getOrderId()); sql.params().set("orderId", dto.getOrderId());
sql.setCallback(Sqls.callback.records()); sql.setCallback(Sqls.callback.records());
@@ -136,33 +182,126 @@ public class PointsMallBridgeServiceImpl implements PointsMallBridgeService {
return MallOutboundResult.success(list); return MallOutboundResult.success(list);
} }
private PointsMallSupplier checkedSupplier(String supplierId, String clientId, String clientSecret, String timestamp) { @Override
if (StrUtil.hasBlank(supplierId, clientId, clientSecret, timestamp)) { public MallOutboundResult applyInvoice(MallInvoiceApplyDTO dto) {
throw new IllegalArgumentException("供应商认证参数不能为空"); if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getSettlementId(), dto.getOrderIds())) {
return MallOutboundResult.fail(400, "开票申请参数不能为空");
}
List<String> orderIds = splitIds(dto.getOrderIds());
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, "未找到可开票订单");
}
if (dto.getOrderNum() != null && dto.getOrderNum() != orders.size()) {
return MallOutboundResult.fail(400, "订单数量与开票申请不一致");
}
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, "订单金额与开票申请不一致");
}
Trans.exec((Atom) () -> saveInvoiceApply(dto, orderIds, total));
return MallOutboundResult.success();
}
@Override
public GetInvoiceInfoDTO queryInvoicesInfo(QueryInvoiceInfoDTO dto) {
if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getSettlementId())) {
throw new IllegalArgumentException("发票查询参数不能为空");
}
PointsMallInvoiceMain main = dao.fetch(PointsMallInvoiceMain.class, Cnd.where("settlementId", "=", dto.getSettlementId())
.and("delFlag", "=", false));
if (main == null) {
throw new IllegalArgumentException("发票信息不存在");
}
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;
}
@Override
public MallPictureOutboundResult queryFileBase64Info(PictureQueryDTO dto) {
if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getQueryType(), dto.getIdNumber())) {
return MallPictureOutboundResult.fail(400, "图片查询参数不能为空");
}
Map<String, String> map = "2".equals(dto.getQueryType()) ? queryInvoiceFiles(dto) : queryProductPictures(dto);
MallPictureOutboundResult result = MallPictureOutboundResult.success(map);
if ("2".equals(dto.getQueryType())) {
result.setFileType(firstInvoiceFileType(dto));
}
return result;
}
@Override
public MallInboundResult unReconciledMsg(UnReconciledMsgNoticeDTO dto) {
if (dto == null || StrUtil.hasBlank(dto.getSupplierId(), dto.getOrderIds())) {
return MallInboundResult.fail(400, "对账异常通知参数不能为空");
}
List<String> orderIds = splitIds(dto.getOrderIds());
Trans.exec((Atom) () -> {
for (String orderId : orderIds) {
PointsMallReconciliationRecord record = new PointsMallReconciliationRecord();
record.setSupplierId(dto.getSupplierId());
record.setOrderId(orderId);
record.setDiffReason(dto.getUnReconciledMsg());
record.setDiffType(Convert.toInt(dto.getUnReconciledType(), null));
record.setBatchNo(StrUtil.blankToDefault(dto.getUniqueSeqNo(), dto.getStartDate() + "_" + dto.getEndDate()));
record.setNoticeStatus(1);
record.setPushTime(1);
dao.insert(record);
}
});
return MallInboundResult.success();
}
@Override
public MallInboundResult payCompletion(OrderPayFinishNoticeDTO dto) {
if (dto == null || StrUtil.isBlank(dto.getSupplierId()) || dto.getExpFinalInfos() == null) {
return MallInboundResult.fail(400, "支付完成通知参数不能为空");
}
Trans.exec((Atom) () -> {
for (FinalStatementDTO item : dto.getExpFinalInfos()) {
if (item == null || StrUtil.isBlank(item.getSettlementId())) {
continue;
}
PointsMallInvoiceMain main = dao.fetch(PointsMallInvoiceMain.class, Cnd.where("settlementId", "=", item.getSettlementId())
.and("delFlag", "=", false));
if (main != null) {
main.setBSuccess(1);
dao.updateIgnoreNull(main);
}
List<String> orderIds = splitIds(item.getOrderIds());
if (!orderIds.isEmpty()) {
dao.update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 1), Cnd.where("supplierId", "=", dto.getSupplierId()).and("orderId", "in", orderIds));
}
}
});
return MallInboundResult.success();
}
private PointsMallSupplier checkedSupplier(String supplierId, String clientId, String clientSecret, String sendSha256, String timestamp) {
if (StrUtil.hasBlank(supplierId, clientId, clientSecret, sendSha256, timestamp)) {
throw new IllegalArgumentException("供应商授权信息不能为空");
} }
PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class, Cnd.where("supplierId", "=", supplierId) PointsMallSupplier supplier = dao.fetch(PointsMallSupplier.class, Cnd.where("supplierId", "=", supplierId)
.and("clientId", "=", clientId).and("delFlag", "=", false)); .and("clientId", "=", clientId).and("delFlag", "=", false));
if (supplier == null) { if (supplier == null) {
throw new IllegalArgumentException("供应商和客户端信息不匹配"); throw new IllegalArgumentException("供应商不存在或已停用");
} }
String serverSha256 = SecureUtil.sha256(supplier.getClientId() + supplier.getClientSecret() + timestamp + clientSecret); String serverSha256 = SecureUtil.sha256(supplier.getClientId() + supplier.getClientSecret() + timestamp);
if (!Objects.equals(clientSecret, serverSha256)) { if (!Objects.equals(sendSha256, serverSha256)) {
throw new IllegalArgumentException("签名验证信息错误"); throw new IllegalArgumentException("签名验证信息错误");
} }
return supplier; return supplier;
} }
private void validateToken(String supplierId, String token) {
if (StrUtil.hasBlank(supplierId, token)) {
throw new IllegalArgumentException("供应商ID和token不能为空");
}
PointsMallSupplierTokenStore store = dao.fetch(PointsMallSupplierTokenStore.class, Cnd.where("supplierId", "=", supplierId)
.and("accessToken", "=", token).and("isValid", "=", true));
if (store == null || store.getAccessExpireTime() == null || new Date().after(store.getAccessExpireTime())) {
throw new IllegalArgumentException("token无效或已过期");
}
}
private MallInboundTokenResult createToken(PointsMallSupplier supplier) { private MallInboundTokenResult createToken(PointsMallSupplier supplier) {
String accessToken = UUID.randomUUID().toString().replace("-", ""); String accessToken = UUID.randomUUID().toString().replace("-", "");
String refreshToken = UUID.randomUUID().toString().replace("-", ""); String refreshToken = UUID.randomUUID().toString().replace("-", "");
@@ -184,7 +323,8 @@ public class PointsMallBridgeServiceImpl implements PointsMallBridgeService {
} }
private MallInboundResult updateMainOrderPay(String supplierId, String orderId, Integer cashPaid, BigDecimal totalPrice, BigDecimal cash, BigDecimal points) { private MallInboundResult updateMainOrderPay(String supplierId, String orderId, Integer cashPaid, BigDecimal totalPrice, BigDecimal cash, BigDecimal points) {
PointsMallOrderMain main = dao.fetch(PointsMallOrderMain.class, Cnd.where("supplierId", "=", supplierId).and("orderId", "=", orderId).and("delFlag", "=", false)); PointsMallOrderMain main = dao.fetch(PointsMallOrderMain.class, Cnd.where("supplierId", "=", supplierId)
.and("orderId", "=", orderId).and("delFlag", "=", false));
if (main == null) { if (main == null) {
return MallInboundResult.fail(404, "订单不存在"); return MallInboundResult.fail(404, "订单不存在");
} }
@@ -192,26 +332,61 @@ public class PointsMallBridgeServiceImpl implements PointsMallBridgeService {
main.setTotalPrice(nvl(totalPrice, main.getTotalPrice())); main.setTotalPrice(nvl(totalPrice, main.getTotalPrice()));
main.setWPayOrAPay(nvl(cash, main.getWPayOrAPay())); main.setWPayOrAPay(nvl(cash, main.getWPayOrAPay()));
main.setPointsPrice(nvl(points, main.getPointsPrice())); main.setPointsPrice(nvl(points, main.getPointsPrice()));
main.setOrderState(cashPaid == 1 ? 1 : main.getOrderState()); main.setOrderState(cashPaid == 1 ? ORDER_FINISH_PAY : main.getOrderState());
main.setOrderUpdateTime(new Date()); main.setOrderUpdateTime(new Date());
dao.updateIgnoreNull(main); dao.updateIgnoreNull(main);
return MallInboundResult.success(); return MallInboundResult.success();
} }
private MallInboundResult cancelMainOrder(MallOrderEventDTO dto, boolean paidNotSplit) {
String mainOrderId = StrUtil.blankToDefault(dto.getMainOrderId(), dto.getOrderId());
if (StrUtil.isBlank(mainOrderId)) {
return MallInboundResult.fail(400, "主订单信息不能为空");
}
PointsMallOrderMain main = dao.fetch(PointsMallOrderMain.class, Cnd.where("supplierId", "=", dto.getSupplierId())
.and("orderId", "=", mainOrderId).and("delFlag", "=", false));
if (main == null) {
return MallInboundResult.fail(404, "主订单不存在");
}
if (!paidNotSplit && !Integer.valueOf(ORDER_PENDING_PAY).equals(main.getOrderState())) {
return MallInboundResult.fail(400, "只能取消未支付主单");
}
main.setOrderState(ORDER_CANCELLED);
main.setOrderUpdateTime(new Date());
dao.updateIgnoreNull(main);
dao.update(PointsMallOrderSub.class, Chain.make("orderState", ORDER_CANCELLED).add("orderUpdateTime", new Date()),
Cnd.where("supplierId", "=", dto.getSupplierId()).and("mainOrderId", "=", mainOrderId).and("delFlag", "=", false));
return MallInboundResult.success();
}
private MallInboundResult splitSubOrder(MallOrderEventDTO dto) { private MallInboundResult splitSubOrder(MallOrderEventDTO dto) {
PointsMallOrderMain main = dao.fetch(PointsMallOrderMain.class, Cnd.where("supplierId", "=", dto.getSupplierId()) PointsMallOrderMain main = dao.fetch(PointsMallOrderMain.class, Cnd.where("supplierId", "=", dto.getSupplierId())
.and("orderId", "=", dto.getMainOrderId()).and("delFlag", "=", false)); .and("orderId", "=", dto.getMainOrderId()).and("delFlag", "=", false));
if (main == null) { if (main == null) {
return MallInboundResult.fail(404, "主订单不存在"); return MallInboundResult.fail(404, "主订单不存在");
} }
if (dao.count(PointsMallOrderSub.class, Cnd.where("orderId", "=", dto.getOrderId()).and("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false)) > 0) { List<String> subOrderIds = splitIds(dto.getOrderId());
return MallInboundResult.fail(-1, "子订单已存在"); if (subOrderIds.isEmpty()) {
return MallInboundResult.fail(400, "子订单信息不能为空");
} }
List<OrderProInfoDTO> products = StrUtil.isBlank(main.getExtJson()) || "null".equalsIgnoreCase(main.getExtJson())
? Collections.emptyList()
: JSONUtil.toList(main.getExtJson(), OrderProInfoDTO.class);
Trans.exec((Atom) () -> { Trans.exec((Atom) () -> {
PointsMallOrderSub sub = toSub(main, dto.getOrderId()); for (String subOrderId : subOrderIds) {
dao.insert(sub); PointsMallOrderSub sub = dao.fetch(PointsMallOrderSub.class, Cnd.where("orderId", "=", subOrderId)
List<OrderProInfoDTO> products = StrUtil.isBlank(main.getExtJson()) || "null".equalsIgnoreCase(main.getExtJson()) ? Collections.emptyList() : JSONUtil.toList(main.getExtJson(), OrderProInfoDTO.class); .and("supplierId", "=", dto.getSupplierId()).and("delFlag", "=", false));
insertProducts(dto.getOrderId(), products); if (sub == null) {
sub = toSub(main, subOrderId);
sub.setOrderState(ORDER_IN_PROGRESS);
dao.insert(sub);
insertProducts(subOrderId, products);
} else {
sub.setOrderState(ORDER_IN_PROGRESS);
sub.setOrderUpdateTime(new Date());
dao.updateIgnoreNull(sub);
}
}
}); });
return MallInboundResult.success(); return MallInboundResult.success();
} }
@@ -224,16 +399,105 @@ public class PointsMallBridgeServiceImpl implements PointsMallBridgeService {
} }
sub.setOrderState(state); sub.setOrderState(state);
sub.setOrderUpdateTime(new Date()); sub.setOrderUpdateTime(new Date());
if (state == 4) { if (state == ORDER_RECEIVED) {
sub.setOrderFinishTime(new Date()); sub.setOrderFinishTime(new Date());
} }
if (state == 5) { if (state == ORDER_COMPLETED) {
sub.setOrderCompleteTime(new Date()); sub.setOrderCompleteTime(new Date());
} }
dao.updateIgnoreNull(sub); dao.updateIgnoreNull(sub);
return MallInboundResult.success(); return MallInboundResult.success();
} }
private MallInboundResult markInvoiceNotice(MallOrderEventDTO dto) {
String mainOrderId = StrUtil.blankToDefault(dto.getMainOrderId(), dto.getOrderId());
if (StrUtil.isBlank(mainOrderId)) {
return MallInboundResult.fail(400, "主订单信息不能为空");
}
dao.update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 1), Cnd.where("supplierId", "=", dto.getSupplierId())
.and("mainOrderId", "=", mainOrderId).and("delFlag", "=", false));
return MallInboundResult.success();
}
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);
}
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);
dao.update(PointsMallOrderSub.class, Chain.make("invoiceStatus", 2).add("invoiceCode", dto.getSettlementId()),
Cnd.where("supplierId", "=", dto.getSupplierId()).and("orderId", "in", orderIds));
}
private Map<String, String> queryProductPictures(PictureQueryDTO dto) {
Cnd cnd = Cnd.where("orderSubId", "=", dto.getIdNumber()).and("delFlag", "=", false);
if (dto.getFileIdList() != null && !dto.getFileIdList().isEmpty()) {
cnd.and("sku", "in", dto.getFileIdList());
}
List<PointsMallOrderSubProduct> products = dao.query(PointsMallOrderSubProduct.class, cnd);
Map<String, String> map = new LinkedHashMap<>();
for (PointsMallOrderSubProduct product : products) {
map.put(product.getSku(), product.getPicInfo());
}
return map;
}
private Map<String, String> queryInvoiceFiles(PictureQueryDTO dto) {
PointsMallInvoiceMain main = dao.fetch(PointsMallInvoiceMain.class, Cnd.where("settlementId", "=", dto.getIdNumber()).and("delFlag", "=", false));
if (main == null) {
return Collections.emptyMap();
}
Cnd cnd = Cnd.where("mainId", "=", main.getId()).and("delFlag", "=", false);
if (dto.getFileIdList() != null && !dto.getFileIdList().isEmpty()) {
cnd.and("invoiceId", "in", dto.getFileIdList());
}
List<PointsMallInvoiceInfo> invoices = dao.query(PointsMallInvoiceInfo.class, cnd);
Map<String, String> map = new LinkedHashMap<>();
for (PointsMallInvoiceInfo invoice : invoices) {
map.put(invoice.getInvoiceId(), invoice.getImageEncode());
}
return map;
}
private String firstInvoiceFileType(PictureQueryDTO dto) {
PointsMallInvoiceMain main = dao.fetch(PointsMallInvoiceMain.class, Cnd.where("settlementId", "=", dto.getIdNumber()).and("delFlag", "=", false));
if (main == null) {
return null;
}
PointsMallInvoiceInfo info = dao.fetch(PointsMallInvoiceInfo.class, Cnd.where("mainId", "=", main.getId()).and("delFlag", "=", false));
return info == null ? null : info.getFileType();
}
private PointsMallOrderMain toMain(String supplierId, String userId, OrderInfoDTO orderInfo, Integer state) { private PointsMallOrderMain toMain(String supplierId, String userId, OrderInfoDTO orderInfo, Integer state) {
PointsMallOrderMain main = new PointsMallOrderMain(); PointsMallOrderMain main = new PointsMallOrderMain();
main.setOrderId(orderInfo.getOrderId()); main.setOrderId(orderInfo.getOrderId());
@@ -313,9 +577,16 @@ public class PointsMallBridgeServiceImpl implements PointsMallBridgeService {
dto.setOrderNumberId(record.getString("orderNumberId")); dto.setOrderNumberId(record.getString("orderNumberId"));
dto.setSupplierId(record.getString("supplierId")); dto.setSupplierId(record.getString("supplierId"));
dto.setAplName(record.getString("aplName")); dto.setAplName(record.getString("aplName"));
dto.setCreateTime(formatDate(record.get("orderCreateTime")));
dto.setUpdateTime(formatDate(record.get("orderUpdateTime")));
dto.setDeliveryTime(formatDate(record.get("deliveryTime")));
dto.setOrderFinishTime(formatDate(record.get("orderFinishTime")));
dto.setCompleteTime(formatDate(record.get("orderCompleteTime")));
dto.setDeliveryStatus(record.getString("deliveryStatus")); dto.setDeliveryStatus(record.getString("deliveryStatus"));
dto.setFreightCost(decimal(record.get("freightCost"))); dto.setFreightCost(decimal(record.get("freightCost")));
dto.setWPayOrAPayFreightCost(decimal(record.get("wPayOrAPayFreightCost")));
dto.setRefund(decimal(record.get("refund"))); dto.setRefund(decimal(record.get("refund")));
dto.setWPayOrAPayRefund(decimal(record.get("wPayOrAPayRefund")));
dto.setLogisticsOrderId(record.getString("logisticsOrderId")); dto.setLogisticsOrderId(record.getString("logisticsOrderId"));
dto.setCrrgBsnNm(record.getString("crrgBsnNm")); dto.setCrrgBsnNm(record.getString("crrgBsnNm"));
dto.setOrderState(record.getInt("orderState")); dto.setOrderState(record.getInt("orderState"));
@@ -323,6 +594,49 @@ public class PointsMallBridgeServiceImpl implements PointsMallBridgeService {
dto.setWPayOrAPay(decimal(record.get("wPayOrAPay"))); dto.setWPayOrAPay(decimal(record.get("wPayOrAPay")));
dto.setPointsPrice(decimal(record.get("pointsPrice"))); dto.setPointsPrice(decimal(record.get("pointsPrice")));
dto.setInvoiceCode(record.getString("invoiceCode")); dto.setInvoiceCode(record.getString("invoiceCode"));
dto.setOrderProInfos(readProducts(dto.getOrderId(), record.getString("extJson")));
return dto;
}
private List<OrderProInfoDTO> readProducts(String orderId, String extJson) {
List<PointsMallOrderSubProduct> products = dao.query(PointsMallOrderSubProduct.class, Cnd.where("orderSubId", "=", orderId).and("delFlag", "=", false));
if (!products.isEmpty()) {
return products.stream().map(this::toProductDTO).collect(Collectors.toList());
}
if (StrUtil.isBlank(extJson) || "null".equalsIgnoreCase(extJson)) {
return Collections.emptyList();
}
return JSONUtil.toList(extJson, OrderProInfoDTO.class);
}
private OrderProInfoDTO toProductDTO(PointsMallOrderSubProduct product) {
OrderProInfoDTO dto = new OrderProInfoDTO();
dto.setSku(product.getSku());
dto.setNumber(product.getNumber());
dto.setPrice(product.getPrice());
dto.setName(product.getName());
dto.setTaxRate(product.getTaxRate());
dto.setPicInfo(StrUtil.isBlank(product.getPicInfo()) ? Collections.emptyList() : Collections.singletonList(product.getPicInfo()));
dto.setFileId(product.getSku());
dto.setFilePath(product.getPicInfo());
return dto;
}
private InvoiceInfoDTO toInvoiceInfoDTO(PointsMallInvoiceInfo info) {
InvoiceInfoDTO dto = new InvoiceInfoDTO();
dto.setInvoiceId(info.getInvoiceId());
dto.setInvoiceCode(info.getInvoiceCode());
dto.setInvoiceDate(toLocalDate(info.getInvoiceDate()));
dto.setInvoiceNakeAmount(info.getInvoiceNakeAmount());
dto.setInvoiceTaxRate(info.getInvoiceTaxRate());
dto.setInvoiceTaxAmount(info.getInvoiceTaxAmount());
dto.setInvoiceAmount(info.getInvoiceAmount());
dto.setInvoiceType(info.getInvoiceType());
dto.setUrl(info.getUrl());
dto.setImageEncode(info.getImageEncode());
dto.setFileType(info.getFileType());
dto.setCheckCode(info.getCheckCode());
dto.setInvoiceAddress(info.getInvoiceAddress());
return dto; return dto;
} }
@@ -333,6 +647,28 @@ public class PointsMallBridgeServiceImpl implements PointsMallBridgeService {
return DateUtil.parse(value.replace("T", " ")); return DateUtil.parse(value.replace("T", " "));
} }
private String formatDate(Object value) {
if (value == null) {
return null;
}
return DateUtil.format(Convert.toDate(value), "yyyy-MM-dd HH:mm:ss");
}
private LocalDate toLocalDate(Date date) {
return date == null ? null : date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
}
private List<String> splitIds(String value) {
if (StrUtil.isBlank(value)) {
return Collections.emptyList();
}
return Arrays.stream(value.split(","))
.map(String::trim)
.filter(StrUtil::isNotBlank)
.distinct()
.collect(Collectors.toList());
}
private BigDecimal nvl(BigDecimal value) { private BigDecimal nvl(BigDecimal value) {
return value == null ? BigDecimal.ZERO : value; return value == null ? BigDecimal.ZERO : value;
} }
@@ -349,10 +685,6 @@ public class PointsMallBridgeServiceImpl implements PointsMallBridgeService {
if (StrUtil.isBlank(value)) { if (StrUtil.isBlank(value)) {
return null; return null;
} }
try { return Convert.toInt(value, null);
return Integer.valueOf(value);
} catch (NumberFormatException e) {
return null;
}
} }
} }
@@ -0,0 +1,86 @@
package com.budwk.app.zhgh.pointsmall.order.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderExchange;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
import com.budwk.app.zhgh.pointsmall.order.param.PointsMallOrderPageParam;
import com.budwk.app.zhgh.pointsmall.order.service.PointsMallOrderService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.adaptor.JsonAdaptor;
import org.nutz.mvc.annotation.AdaptBy;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.annotation.POST;
@IocBean
@Ok("json:full")
@At("/platform/zhgh/points-mall/order/sub")
@AdaptBy(type = JsonAdaptor.class)
public class PointsMallOrderSubController {
@Inject
private PointsMallOrderService pointsMallOrderService;
@POST
@At("/page")
@SaCheckPermission("points.mall.order")
public Result pageData(@Param("..") PointsMallOrderPageParam param) {
return Result.success(pointsMallOrderService.pageSub(param));
}
@POST
@At("/product")
@SaCheckPermission("points.mall.order")
public Result productList(@Param("orderId") String orderId) {
return Result.success(pointsMallOrderService.listSubProducts(orderId));
}
@POST
@At("/exchange/list")
@SaCheckPermission("points.mall.order")
public Result exchangeList(@Param("mainOrderId") String mainOrderId) {
return Result.success(pointsMallOrderService.listExchange(mainOrderId));
}
@POST
@At("/exchange/product")
@SaCheckPermission("points.mall.order")
public Result exchangeProductList(@Param("orderId") String orderId) {
return Result.success(pointsMallOrderService.listExchangeProducts(orderId));
}
@POST
@At("/update")
@SaCheckPermission("points.mall.order")
public Result update(@Param("..") PointsMallOrderSub orderSub) {
return result(pointsMallOrderService.updateSub(orderSub));
}
@POST
@At("/delete")
@SaCheckPermission("points.mall.order")
public Result delete(@Param("id") String id) {
return result(pointsMallOrderService.deleteSub(id));
}
@POST
@At("/exchange/update")
@SaCheckPermission("points.mall.order")
public Result updateExchange(@Param("..") PointsMallOrderExchange exchange) {
return result(pointsMallOrderService.updateExchange(exchange));
}
@POST
@At("/exchange/delete")
@SaCheckPermission("points.mall.order")
public Result deleteExchange(@Param("id") String id) {
return result(pointsMallOrderService.deleteExchange(id));
}
private Result result(boolean success) {
return success ? Result.success("操作成功") : Result.error("操作失败");
}
}
@@ -3,6 +3,8 @@ package com.budwk.app.zhgh.pointsmall.order.service;
import com.budwk.app.base.page.Pagination; import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.BaseService; import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderMain; import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderMain;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderExchange;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
import com.budwk.app.zhgh.pointsmall.order.param.PointsMallMobileOrderPageParam; import com.budwk.app.zhgh.pointsmall.order.param.PointsMallMobileOrderPageParam;
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier; import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
import com.budwk.app.zhgh.pointsmall.order.param.PointsMallOrderPageParam; import com.budwk.app.zhgh.pointsmall.order.param.PointsMallOrderPageParam;
@@ -28,5 +30,13 @@ public interface PointsMallOrderService extends BaseService<PointsMallOrderMain>
List<Record> listExchangeProducts(String orderId); List<Record> listExchangeProducts(String orderId);
boolean updateSub(PointsMallOrderSub orderSub);
boolean deleteSub(String id);
boolean updateExchange(PointsMallOrderExchange exchange);
boolean deleteExchange(String id);
List<PointsMallSupplier> listSuppliers(); List<PointsMallSupplier> listSuppliers();
} }
@@ -3,19 +3,23 @@ package com.budwk.app.zhgh.pointsmall.order.service.impl;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination; import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.impl.BaseServiceImpl; import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderExchange;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderMain; import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderMain;
import com.budwk.app.zhgh.pointsmall.order.models.PointsMallOrderSub;
import com.budwk.app.zhgh.pointsmall.order.param.PointsMallMobileOrderPageParam; import com.budwk.app.zhgh.pointsmall.order.param.PointsMallMobileOrderPageParam;
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
import com.budwk.app.zhgh.pointsmall.order.param.PointsMallOrderPageParam; import com.budwk.app.zhgh.pointsmall.order.param.PointsMallOrderPageParam;
import com.budwk.app.zhgh.pointsmall.order.service.PointsMallOrderService; import com.budwk.app.zhgh.pointsmall.order.service.PointsMallOrderService;
import com.budwk.app.zhgh.pointsmall.supplier.models.PointsMallSupplier;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd; import org.nutz.dao.Cnd;
import org.nutz.dao.Dao; import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.entity.Record; import org.nutz.dao.entity.Record;
import org.nutz.dao.sql.Sql; import org.nutz.dao.sql.Sql;
import org.nutz.dao.Sqls;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date;
import java.util.List; import java.util.List;
@IocBean(args = {"refer:dao"}) @IocBean(args = {"refer:dao"})
@@ -97,10 +101,12 @@ public class PointsMallOrderServiceImpl extends BaseServiceImpl<PointsMallOrderM
state(0, "待付款"), state(0, "待付款"),
state(1, "已支付"), state(1, "已支付"),
state(2, "进行中"), state(2, "进行中"),
state(4, "签收"), state(3, "取消"),
state(4, "已妥投"),
state(5, "已完成"), state(5, "已完成"),
state(6, "换货"), state(6, "换货"),
state(7, "退货") state(7, "退货"),
state(8, "已废除")
); );
} }
@@ -145,6 +151,40 @@ public class PointsMallOrderServiceImpl extends BaseServiceImpl<PointsMallOrderM
return listSubProducts(orderId); return listSubProducts(orderId);
} }
@Override
public boolean updateSub(PointsMallOrderSub orderSub) {
if (orderSub == null || StrUtil.isBlank(orderSub.getId())) {
return false;
}
orderSub.setOrderUpdateTime(new Date());
return dao().updateIgnoreNull(orderSub) > 0;
}
@Override
public boolean deleteSub(String id) {
if (StrUtil.isBlank(id)) {
return false;
}
return dao().update(PointsMallOrderSub.class, Chain.make("delFlag", true), Cnd.where("id", "=", id)) > 0;
}
@Override
public boolean updateExchange(PointsMallOrderExchange exchange) {
if (exchange == null || StrUtil.isBlank(exchange.getId())) {
return false;
}
exchange.setOrderUpdateTime(new Date());
return dao().updateIgnoreNull(exchange) > 0;
}
@Override
public boolean deleteExchange(String id) {
if (StrUtil.isBlank(id)) {
return false;
}
return dao().update(PointsMallOrderExchange.class, Chain.make("delFlag", true), Cnd.where("id", "=", id)) > 0;
}
@Override @Override
public List<PointsMallSupplier> listSuppliers() { public List<PointsMallSupplier> listSuppliers() {
return dao().query(PointsMallSupplier.class, Cnd.where("delFlag", "=", false).asc("sortCode")); return dao().query(PointsMallSupplier.class, Cnd.where("delFlag", "=", false).asc("sortCode"));
@@ -84,6 +84,7 @@ layout("/layouts/platform_h5.html"){
<script nonce="${cspNonce!}"> <script nonce="${cspNonce!}">
new Vue({ new Vue({
el: "#app", el: "#app",
store,
data() { data() {
return { return {
keyword: "", keyword: "",
@@ -145,12 +146,36 @@ layout("/layouts/platform_h5.html"){
this.userPoints = resp.data || 0 this.userPoints = resp.data || 0
} }
}, },
openSupplier(item) { async openSupplier(item) {
if (!item.supplierUrl) { if (!item.supplierUrl) {
this.$toast("暂无跳转地址") this.$toast("暂无跳转地址")
return return
} }
window.location.href = item.supplierUrl const userId = this.$store && this.$store.state.user ? this.$store.state.user.id : ""
if (!userId) {
this.$toast("获取用户信息失败,请重新登录后再试")
return
}
window.location.href = this.withSupplierQuery(item.supplierUrl, {
userId: userId
})
},
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
}, },
onImgError(e) { onImgError(e) {
e.target.src = this.defaultLogo e.target.src = this.defaultLogo