master
ljw 2025-11-11 09:33:16 +08:00
parent ca40e8260f
commit d6cbc62e5c
8 changed files with 178 additions and 10 deletions

View File

@ -5,6 +5,8 @@ import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
/**
*
*/
@ -27,7 +29,7 @@ public class RegulationParam {
/**
*
*/
private String delta;
private BigDecimal delta;
/**
*

View File

@ -3,14 +3,24 @@ package com.njzscloud.supervisory.order.service;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.supervisory.expense.contant.ExpenseItemCategory;
import com.njzscloud.supervisory.money.contant.MoneyChangeCategory;
import com.njzscloud.supervisory.money.pojo.entity.MoneyAccountEntity;
import com.njzscloud.supervisory.money.pojo.entity.MoneyChangeDetailEntity;
import com.njzscloud.supervisory.money.service.MoneyAccountService;
import com.njzscloud.supervisory.money.service.MoneyChangeDetailService;
import com.njzscloud.supervisory.order.pojo.entity.OrderExpenseItemsEntity;
import com.njzscloud.supervisory.order.pojo.entity.OrderInfoEntity;
import com.njzscloud.supervisory.order.pojo.param.ChangePriceParam;
import com.njzscloud.supervisory.order.pojo.param.RegulationParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.YearMonth;
/**
*
*/
@ -21,13 +31,72 @@ public class AccountRegulationService {
private final OrderInfoService orderInfoService;
private final MoneyAccountService moneyAccountService;
private final MoneyChangeDetailService moneyChangeDetailService;
private final OrderExpenseItemsService orderExpenseItemsService;
/**
*
*/
@Transactional(rollbackFor = Exception.class)
public void accountRegulation(RegulationParam param) {
OrderInfoEntity order = orderInfoService.getOne(Wrappers.<OrderInfoEntity>lambdaQuery().eq(OrderInfoEntity::getSn, param.getSn()));
Assert.notNull(order, () -> Exceptions.clierr("订单不存在"));
OrderInfoEntity order = orderInfoService.getOne(Wrappers.<OrderInfoEntity>lambdaQuery()
.eq(OrderInfoEntity::getSn, param.getSn())
.eq(OrderInfoEntity::getTransCompanyId, param.getCompanyId()));
Assert.notNull(order, () -> Exceptions.clierr("当前客户不存在该笔订单,请检查订单号是否正确"));
// 判断订单创建时间是否在当月
LocalDateTime createTime = order.getCreateTime();
if (createTime != null) {
YearMonth orderMonth = YearMonth.from(createTime);
YearMonth currentMonth = YearMonth.now();
boolean isCurrentMonth = orderMonth.equals(currentMonth);
if (!isCurrentMonth) {
throw Exceptions.clierr("只能对当月订单调账");
}
}
// 新增一条付费项
OrderExpenseItemsEntity productItem = new OrderExpenseItemsEntity()
.setExpenseItemCategory(ExpenseItemCategory.ChanPin.getVal())
.setOrderId(order.getId())
.setOriginExpenseItemId(202511081532L)
.setExpenseItemName("业务调账")
.setUnitPrice(new BigDecimal("0"))
.setUnit("Che")
.setMoneyStrategy("Che")
.setQuantity(1)
.setTotalMoney(param.getDelta())
.setSettleMoney(param.getDelta());
orderExpenseItemsService.save(productItem);
// 查询账户
MoneyAccountEntity accountEntity = moneyAccountService.getOne(Wrappers.<MoneyAccountEntity>lambdaQuery()
.eq(MoneyAccountEntity::getStationId, param.getCompanyId()));
if (null == accountEntity) {
throw Exceptions.clierr("资金账户不存在");
}
BigDecimal newMoney = accountEntity.getMoney().add(param.getDelta());
// 新增一条资金明细
MoneyChangeDetailEntity changeDetail = new MoneyChangeDetailEntity()
.setCompanyId(param.getCompanyId())
.setOrderId(order.getId())
.setMoneyAccountId(accountEntity.getId())
.setOldMoney(accountEntity.getMoney())
.setDelta(param.getDelta())
.setNewMoney(newMoney)
.setMoneyChangeCategory(MoneyChangeCategory.DingDanTiaoZhang)
.setMemo(param.getMemo());
moneyChangeDetailService.save(changeDetail);
// 变更资金账户金额
MoneyAccountEntity companyAccount = new MoneyAccountEntity()
.setId(accountEntity.getId())
.setMoney(newMoney);
moneyAccountService.updateById(companyAccount);
}

View File

@ -19,5 +19,7 @@ public class WxApiConfig {
public static final String SEND_TEMPLATE_MSG_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
public static final String TICKET_URL = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=";
}

View File

@ -23,11 +23,19 @@ public class WechatTemplateMessageController {
* openid
*/
@GetMapping("/bind")
public R<?> detail(@RequestParam String code) {
public R<?> bind(@RequestParam String code) {
wechatTemplateMessageService.bind(code);
return R.success();
}
/**
* key
*/
@GetMapping("/key")
public R<?> key() {
return R.success(wechatTemplateMessageService.key());
}
@PostMapping("/send-order-notice")
public String sendOrderNotice(@RequestBody TemplateMessageParam param) {
try {

View File

@ -13,6 +13,8 @@ public interface WechatTemplateMessageService {
void bind(String code);
Map<String, Object> key();
/**
*
*/

View File

@ -19,8 +19,12 @@ import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
*
@ -69,12 +73,40 @@ public class WechatTemplateMessageServiceImpl implements WechatTemplateMessageSe
}
@Override
public Map<String, Object> key() {
RestTemplate restTemplate = new RestTemplate();
// 1. 获取Access Token
String accessToken = getAccessToken();
String response = restTemplate.postForObject(WxApiConfig.TICKET_URL + accessToken + "&type=jsapi", "", String.class);
// 5. 处理响应
JSONObject jsonResponse = JSONObject.parseObject(response);
if (null == jsonResponse) {
throw Exceptions.clierr("获取ticket失败jsonResponse为null");
}
if (jsonResponse.getIntValue("errcode") != 0) {
log.error("发送模板消息失败: " + jsonResponse.getString("errmsg"));
}
String jsapi_ticket = jsonResponse.getString("ticket");
String timestamp = Long.toString(System.currentTimeMillis() / 1000); // 必填,生成签名的时间戳
String nonceStr = UUID.randomUUID().toString().replaceAll("-", ""); // 必填,生成签名的随机串
// 注意这里参数名必须全部小写,且必须有序
String signature = getSignature(jsapi_ticket, timestamp, nonceStr, WxApiConfig.REDIRECT_URI);
Map<String, Object> map = new HashMap<>();
map.put("appId", WxApiConfig.APP_ID);
map.put("timestamp", timestamp);
map.put("nonceStr", nonceStr);
map.put("signature", signature);
return map;
}
@Override
public void sendTemplateMessage(TemplateMessageParam param) {
// UserEntity userEntity = userService.getById(param.getUserId());
UserEntity userEntity = new UserEntity();
userEntity.setOpenid("owC-r2Bf1axK1C2MQ6nOaCDbKuHw");
if (null != userEntity && !Strings.isNullOrEmpty(userEntity.getOpenid())) {
if (!Strings.isNullOrEmpty(userEntity.getOpenid())) {
Map<String, TemplateData> data;
if (TempType.TRANS_COMPANY.getVal().equals(param.getTempType())) {
// 通知清运公司指派司机
@ -131,8 +163,8 @@ public class WechatTemplateMessageServiceImpl implements WechatTemplateMessageSe
*
*/
public void sendMessage(String openId, String templateId,
Map<String, TemplateData> data,
String url, String miniProgram) {
Map<String, TemplateData> data,
String url, String miniProgram) {
// 1. 获取Access Token
String accessToken = getAccessToken();
if (Strings.isNullOrEmpty(accessToken)) {
@ -205,4 +237,57 @@ public class WechatTemplateMessageServiceImpl implements WechatTemplateMessageSe
return jsonResponse.getString("access_token");
}
public static String getSignature(String jsapi_ticket, String timestamp,
String nonce, String js_url) {
// 对 jsapi_ticket、 timestamp 和 nonce 按字典排序 对所有待签名参数按照字段名的 ASCII
// 码从小到大排序(字典序)后,使用 URL 键值对的格式即key1=value1&key2=value2…拼接成字符串
// string1。这里需要注意的是所有参数名均为小写字符。 接下来对 string1 作 sha1 加密,字段名和字段值都采用原始值,不进行
// URL 转义。即 signature=sha1(string1)。
// 如果没有按照生成的key1=value&key2=value拼接的话会报错
String[] paramArr = new String[]{"jsapi_ticket=" + jsapi_ticket, "timestamp=" + timestamp, "noncestr=" + nonce,
"url=" + js_url};
Arrays.sort(paramArr);
// 将排序后的结果拼接成一个字符串
String content = paramArr[0].concat("&" + paramArr[1]).concat("&" + paramArr[2]).concat("&" + paramArr[3]);
log.info("拼接之后的content为:" + content);
String genSignature = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
// 对拼接后的字符串进行 sha1 加密
byte[] digest = md.digest(content.getBytes());
genSignature = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
// 将 sha1 加密后的字符串与 signature 进行对比
if (genSignature != null) {
return genSignature;// 返回signature
} else {
return "false";
}
}
/**
*
*/
private static String byteToStr(byte[] byteArray) {
StringBuilder strDigest = new StringBuilder();
for (byte b : byteArray) {
strDigest.append(byteToHexStr(b));
}
return strDigest.toString();
}
/**
*
*/
private static String byteToHexStr(byte mByte) {
char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
'B', 'C', 'D', 'E', 'F'};
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
return new String(tempArr);
}
}

View File

@ -28,7 +28,7 @@ spring:
- /district/areaList
- /biz_audit_config/copy
- /order_info/gps_test
- /wechatTemplateMessage/bind
- /wechatTemplateMessage/key
- /hsoa/push_order
app:
default-place:

View File

@ -26,7 +26,7 @@ spring:
- /payment/wechat/refundNotify
- /district/areaList
- /biz_audit_config/copy
- /wechatTemplateMessage/bind
- /wechatTemplateMessage/key
- /hsoa/push_order
app: