Browse Source

对接拼团数据1

master
wangfukang 2 days ago
parent
commit
3227a40a74
  1. 16
      hiver-admin/test-output/test-report.html
  2. 74
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/DictDataController.java
  3. 18
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/SettingController.java
  4. 3
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/entity/DictData.java
  5. 6
      hiver-modules/hiver-base/src/main/java/cc/hiver/base/serviceimpl/DictDataServiceImpl.java
  6. 1
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ProductController.java
  7. 11
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopAreaController.java
  8. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java
  9. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Product.java
  10. 4
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopArea.java
  11. 25
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderDelayConsumer.java
  12. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/CreateOrderDTO.java
  13. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/ProductPageVO.java
  14. 3
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/ProductVo.java
  15. 54
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java
  16. 64
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java
  17. 58
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuReceiptRenderUtil.java
  18. 2
      hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/cloudprint/CloudReceiptRenderUtil.java
  19. 2
      hiver-modules/hiver-mall/src/main/resources/db/product_more_buy_product_ids.sql
  20. 2
      hiver-modules/hiver-mall/src/main/resources/db/shop_area_campus_text_enabled.sql
  21. 13
      hiver-modules/hiver-mall/src/main/resources/mapper/ProductMapper.xml
  22. 10
      hiver-modules/hiver-social/src/main/java/cc/hiver/social/controller/WechatController.java

16
hiver-admin/test-output/test-report.html

@ -35,7 +35,7 @@
<a href="#"><span class="badge badge-primary">Hiver</span></a>
</li>
<li class="m-r-10">
<a href="#"><span class="badge badge-primary">十月 29, 2026 13:09:25</span></a>
<a href="#"><span class="badge badge-primary">十一月 10, 2026 14:35:16</span></a>
</li>
</ul>
</div>
@ -84,7 +84,7 @@
<div class="test-detail">
<span class="meta text-white badge badge-sm"></span>
<p class="name">passTest</p>
<p class="text-sm"><span>13:09:26 下午</span> / <span>0.023 secs</span></p>
<p class="text-sm"><span>14:35:17 下午</span> / <span>0.03 secs</span></p>
</div>
<div class="test-contents d-none">
<div class="detail-head">
@ -92,9 +92,9 @@
<div class="info">
<div class='float-right'><span class='badge badge-default'>#test-id=1</span></div>
<h5 class="test-status text-pass">passTest</h5>
<span class='badge badge-success'>10.29.2026 13:09:26</span>
<span class='badge badge-danger'>10.29.2026 13:09:26</span>
<span class='badge badge-default'>0.023 secs</span>
<span class='badge badge-success'>11.10.2026 14:35:17</span>
<span class='badge badge-danger'>11.10.2026 14:35:17</span>
<span class='badge badge-default'>0.03 secs</span>
</div>
<div class="m-t-10 m-l-5"></div>
</div>
@ -104,7 +104,7 @@
<tbody>
<tr class="event-row">
<td><span class="badge log pass-bg">Pass</span></td>
<td>13:09:26</td>
<td>14:35:17</td>
<td>
Test passed
</td>
@ -128,13 +128,13 @@
<div class="col-md-3">
<div class="card"><div class="card-body">
<p class="m-b-0">Started</p>
<h3>十月 29, 2026 13:09:25</h3>
<h3>十一月 10, 2026 14:35:16</h3>
</div></div>
</div>
<div class="col-md-3">
<div class="card"><div class="card-body">
<p class="m-b-0">Ended</p>
<h3>十月 29, 2026 13:09:26</h3>
<h3>十一月 10, 2026 14:35:17</h3>
</div></div>
</div>
<div class="col-md-3">

74
hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/DictDataController.java

@ -18,6 +18,7 @@ import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
@ -49,6 +50,8 @@ public class DictDataController {
@ApiOperation(value = "多条件分页获取用户列表")
public Result<Page<DictData>> getByCondition(DictData dictData,
PageVo pageVo) {
pageVo.setSortOrder("sortOrder");
pageVo.setOrderOrder("asc");
List<Object> values = redisTemplate.hValues("DICTDATA_CACHE:" + dictData.getDictId());
if (values != null && !values.isEmpty()) {
List<DictData> allDatas = new ArrayList<>();
@ -56,13 +59,82 @@ public class DictDataController {
DictData dto = JSONUtil.toBean(v.toString(), DictData.class);
allDatas.add(dto);
}
Page<DictData> pageResult = new PageImpl<>(allDatas, PageUtil.initPage(pageVo), allDatas.size());
allDatas = filterByCondition(allDatas, dictData);
allDatas.sort(this::compareBySortOrderAsc);
Pageable pageable = PageUtil.initPage(pageVo);
Page<DictData> pageResult = new PageImpl<>(getPageContent(allDatas, pageable), pageable, allDatas.size());
return new ResultUtil<Page<DictData>>().setData(pageResult);
}
Page<DictData> page = dictDataService.findByCondition(dictData, PageUtil.initPage(pageVo));
return new ResultUtil<Page<DictData>>().setData(page);
}
private int compareBySortOrderAsc(DictData first, DictData second) {
if (first == null && second == null) {
return 0;
}
if (first == null) {
return 1;
}
if (second == null) {
return -1;
}
if (first.getSortOrder() == null && second.getSortOrder() == null) {
return 0;
}
if (first.getSortOrder() == null) {
return 1;
}
if (second.getSortOrder() == null) {
return -1;
}
return first.getSortOrder().compareTo(second.getSortOrder());
}
private List<DictData> filterByCondition(List<DictData> allDatas, DictData condition) {
if (condition == null) {
return allDatas;
}
List<DictData> filteredDatas = new ArrayList<>();
for (DictData data : allDatas) {
if (matchCondition(data, condition)) {
filteredDatas.add(data);
}
}
return filteredDatas;
}
private boolean matchCondition(DictData data, DictData condition) {
if (data == null) {
return false;
}
if (condition.getTitle() != null && !"".equals(condition.getTitle())
&& (data.getTitle() == null || !data.getTitle().contains(condition.getTitle()))) {
return false;
}
if (condition.getStatus() != null && !condition.getStatus().equals(data.getStatus())) {
return false;
}
if (condition.getDictId() != null && !"".equals(condition.getDictId())
&& !condition.getDictId().equals(data.getDictId())) {
return false;
}
if (condition.getMerchantType() != null && !condition.getMerchantType().equals(data.getMerchantType())) {
return false;
}
return true;
}
private List<DictData> getPageContent(List<DictData> allDatas, Pageable pageable) {
int startIndex = (int) pageable.getOffset();
if (startIndex >= allDatas.size()) {
return new ArrayList<>();
}
int endIndex = Math.min(startIndex + pageable.getPageSize(), allDatas.size());
return allDatas.subList(startIndex, endIndex);
}
@RequestMapping(value = "/getByType/{type}", method = RequestMethod.GET)
@ApiOperation(value = "通过类型获取")
@Cacheable(key = "#type")

18
hiver-modules/hiver-base/src/main/java/cc/hiver/base/controller/manage/SettingController.java

@ -34,6 +34,10 @@ import java.util.Map;
@Api(tags = "基本配置接口")
@RequestMapping("/hiver/setting")
public class SettingController {
private static final String APP_UPDATE_OSS_ENDPOINT = "https://jewel-shop.oss-cn-beijing.aliyuncs.com";
private static final String APP_UPDATE_OSS_ENDPOINT_HTTP = "http://jewel-shop.oss-cn-beijing.aliyuncs.com";
private static final String APP_UPDATE_DOWNLOAD_DOMAIN = "https://static.hbkuaishi.com";
@Autowired
private SettingService settingService;
@ -316,6 +320,18 @@ public class SettingController {
if (setting == null || StrUtil.isBlank(setting.getValue())) {
return null;
}
return new Gson().fromJson(setting.getValue(), AppUpdateSetting.class);
AppUpdateSetting appUpdateSetting = new Gson().fromJson(setting.getValue(), AppUpdateSetting.class);
if (appUpdateSetting != null && StrUtil.isNotBlank(appUpdateSetting.getUrl())) {
appUpdateSetting.setUrl(normalizeAppUpdateUrl(appUpdateSetting.getUrl()));
}
return appUpdateSetting;
}
private String normalizeAppUpdateUrl(String url) {
if (StrUtil.isBlank(url)) {
return url;
}
return url.replace(APP_UPDATE_OSS_ENDPOINT, APP_UPDATE_DOWNLOAD_DOMAIN)
.replace(APP_UPDATE_OSS_ENDPOINT_HTTP, APP_UPDATE_DOWNLOAD_DOMAIN);
}
}

3
hiver-modules/hiver-base/src/main/java/cc/hiver/base/entity/DictData.java

@ -39,6 +39,9 @@ public class DictData extends HiverBaseEntity {
@Column(precision = 10, scale = 2)
private BigDecimal sortOrder;
@ApiModelProperty(value = "分类用途 0不区分 1外卖 2团购")
private Integer merchantType;
@ApiModelProperty(value = "是否启用 0启用 -1禁用")
private Integer status = CommonConstant.STATUS_NORMAL;

6
hiver-modules/hiver-base/src/main/java/cc/hiver/base/serviceimpl/DictDataServiceImpl.java

@ -51,6 +51,7 @@ public class DictDataServiceImpl implements DictDataService {
Path<String> titleField = root.get("title");
Path<Integer> statusField = root.get("status");
Path<String> dictIdField = root.get("dictId");
Path<Integer> merchantTypeField = root.get("merchantType");
List<Predicate> list = new ArrayList<>();
@ -69,6 +70,11 @@ public class DictDataServiceImpl implements DictDataService {
list.add(cb.equal(dictIdField, dictData.getDictId()));
}
// 分类用途
if (dictData.getMerchantType() != null) {
list.add(cb.equal(merchantTypeField, dictData.getMerchantType()));
}
Predicate[] arr = new Predicate[list.size()];
cq.where(list.toArray(arr));
return null;

1
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ProductController.java

@ -493,6 +493,7 @@ public class ProductController {
if (CharSequenceUtil.isNotBlank(productPageQuery.getCategoryId()) && !productPageQuery.getCategoryId().equals(p.getCategoryId())) return false;
if (productPageQuery.getIsPush() != null && !productPageQuery.getIsPush().equals(p.getIsPush())) return false;
if (productPageQuery.getIsMust() != null && !productPageQuery.getIsMust().equals(p.getIsMust())) return false;
if (productPageQuery.getIsMoreBuy() != null && !productPageQuery.getIsMoreBuy().equals(p.getIsMoreBuy())) return false;
if (productPageQuery.getDelFlag() != null && !productPageQuery.getDelFlag().equals(p.getDelFlag())) return false;
if (CharSequenceUtil.isNotBlank(productPageQuery.getKeywords())) {
if (p.getProductName() == null || !p.getProductName().contains(productPageQuery.getKeywords())) {

11
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/controller/ShopAreaController.java

@ -313,6 +313,7 @@ public class ShopAreaController {
shopArea.setAreaKind(1);
shopArea.setExpressErrandEnabled(1);
shopArea.setErrandPlanetVisible(1);
shopArea.setCampusTextEnabled(0);
return null;
}
Integer areaKind = shopArea.getAreaKind();
@ -331,6 +332,16 @@ public class ShopAreaController {
return ResultUtil.error("快递/跑腿开关仅支持:1开启,0关闭");
}
}
if (shopArea.getAreaKind() != 2) {
shopArea.setCampusTextEnabled(0);
} else {
Integer campusTextEnabled = shopArea.getCampusTextEnabled();
if (campusTextEnabled == null) {
shopArea.setCampusTextEnabled(0);
} else if (campusTextEnabled != 0 && campusTextEnabled != 1) {
return ResultUtil.error("文案按照校园显示开关仅支持:1开启,0关闭");
}
}
Integer errandPlanetVisible = shopArea.getErrandPlanetVisible();
if (errandPlanetVisible == null) {
shopArea.setErrandPlanetVisible(1);

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/MallOrder.java

@ -84,6 +84,8 @@ public class MallOrder implements Serializable {
private Date shopMakeTime;
@ApiModelProperty(value = "自取订单用户要求出餐 默认mull 1为用户要求")
private Integer userRequireMake;
@ApiModelProperty(value = "自取订单用户预约用餐/取餐时间")
private Date userRequireMakeTime;
@ApiModelProperty(value = "学校id")
private String regionId;
@ApiModelProperty("是否免单")

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/Product.java

@ -140,6 +140,9 @@ public class Product implements Serializable {
@ApiModelProperty(value = "是否为加料 0否 1是")
private Integer isMoreBuy;
@ApiModelProperty(value = "可搭配商品ID,多个用逗号分隔")
private String moreBuyProductIds;
@ApiModelProperty(value = "餐盒费")
private BigDecimal lunchBox;

4
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/entity/ShopArea.java

@ -91,6 +91,10 @@ public class ShopArea extends HiverBaseEntity {
@Column(nullable = false, columnDefinition = "int default 1")
private Integer errandPlanetVisible = 1;
@ApiModelProperty(value = "社会区域文案是否按照校园显示:1开启,0关闭")
@Column(nullable = false, columnDefinition = "int default 0")
private Integer campusTextEnabled = 0;
@Transient
@TableField(exist = false)
@ApiModelProperty(value = "父节点名称")

25
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/mq/OrderDelayConsumer.java

@ -59,6 +59,9 @@ public class OrderDelayConsumer {
@Autowired
private JPushServiceImpl jPushService;
@Autowired
private OrderAsyncProducer orderAsyncProducer;
@Autowired
private cc.hiver.mall.dao.mapper.MallRefundRecordMapper mallRefundRecordMapper;
@ -97,6 +100,9 @@ public class OrderDelayConsumer {
case "Appointment_Shop_Cook_Notify":
handleAppointmentShopCookNotify(orderId);
break;
case "Store_Pickup_Cook_Notify":
handleStorePickupCookNotify(orderId);
break;
case "Transfer_Arrive_Timeout":
handleTransferArriveTimeout(orderId);
break;
@ -265,6 +271,25 @@ public class OrderDelayConsumer {
}
}
private void handleStorePickupCookNotify(String orderId) {
MallOrder order = mallOrderMapper.selectById(orderId);
if (order == null
|| !Integer.valueOf(2).equals(order.getDeliveryType())
|| Integer.valueOf(1).equals(order.getUserRequireMake())
|| order.getUserRequireMakeTime() == null
|| order.getShopMakeTime() != null
|| order.getStatus() == null
|| order.getStatus() >= 4) {
return;
}
log.info("【订单延时处理】预约到店订单到达可出餐时间,向商家发送极光推送并打印 orderId={}", orderId);
Shop shop = shopMapper.selectById(order.getShopId());
if (shop != null && StringUtils.isNotBlank(shop.getClientId())) {
jPushService.sendPushNotification(shop.getClientId(), "您有一笔预约到店订单可以出餐啦!", orderId);
}
orderAsyncProducer.sendCloudPrint(orderId, "SHOP_APPOINTMENT_MAKE");
}
private void handleTransferArriveTimeout(String orderId) {
MallDeliveryOrder delivery = getDeliveryOrder(orderId);
if (delivery == null || !Integer.valueOf(1).equals(delivery.getTransferDelivery())

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/dto/CreateOrderDTO.java

@ -45,6 +45,9 @@ public class CreateOrderDTO {
@ApiModelProperty(value = "自取订单用户要求出餐 默认mull 1为用户要求")
private Integer userRequireMake;
@ApiModelProperty(value = "自取订单用户预约用餐/取餐时间")
private Date userRequireMakeTime;
@ApiModelProperty(value = "送货区域ID(用户收货地址关联区域id)")
private String putAreaId;

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/ProductPageVO.java

@ -159,6 +159,9 @@ public class ProductPageVO {
@ApiModelProperty(value = "是否为加料 0否 1是")
private Integer isMoreBuy;
@ApiModelProperty(value = "可搭配商品ID,多个用逗号分隔")
private String moreBuyProductIds;
@ApiModelProperty(value = "盘点明细")
private List<CheckStockAttributeVo> checkStockAttributeVos;

3
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/pojo/vo/ProductVo.java

@ -107,6 +107,9 @@ public class ProductVo extends HiverBaseEntity {
@ApiModelProperty(value = "是否为加料 0否 1是")
private Integer isMoreBuy;
@ApiModelProperty(value = "可搭配商品ID,多个用逗号分隔")
private String moreBuyProductIds;
@ApiModelProperty(value = "入库状态:0:待入库(未维护对应的采购价信息);1:已入库;新增商品时为已入库")
private Integer inStorageStatus = 1;

54
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderGroupServiceImpl.java

@ -57,6 +57,9 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
private static final int ORDER_STATUS_WAIT_SHOP = 1;
private static final int ORDER_STATUS_CANCELLED = 6;
private static final int ORDER_TYPE_GROUP = 2;
private static final int DELIVERY_TYPE_SELF = 2;
private static final String DELAY_TYPE_STORE_PICKUP_COOK_NOTIFY = "Store_Pickup_Cook_Notify";
private static final long STORE_PICKUP_NOTIFY_BEFORE_MILLIS = 30 * 60 * 1000L;
@Autowired
@Lazy
@ -183,15 +186,6 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
.eq(MallOrder::getStatus, ORDER_STATUS_WAIT_GROUP)
.set(MallOrder::getStatus, targetStatus)
.set(MallOrder::getNumberCode, latestSeq);
if(order.getUserRequireMake() != null && order.getUserRequireMake() == 1){
Shop shop = getShopFromCache(order.getRegionId(), order.getShopId());
if (shop != null && StringUtils.isNotBlank(shop.getClientId())) {
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的到店订单",order.getId());
}
orderAsyncProducer.sendCloudPrint(order.getId(), "SHOP_INSTANT_MAKE");
// 触发商家出餐超时监听
triggerShopCookTimeoutEvent(order);
}
}else{
ouw.eq(MallOrder::getId, order.getId())
.eq(MallOrder::getStatus, ORDER_STATUS_WAIT_GROUP)
@ -202,6 +196,8 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
}
if (targetStatus == 2) {
notifyShopDeliveryOrder(order);
} else if (targetStatus == 3) {
notifyOrScheduleStorePickupMake(order);
}
MallOrderVO orderVO = buildVO(order, null, null, null);
orderVO.setStatus(targetStatus);
@ -355,6 +351,46 @@ public class MallOrderGroupServiceImpl extends ServiceImpl<MallOrderGroupMapper,
} catch (Exception e) {
log.warn("商家自配送订单推送失败 orderId={}: {}", order.getId(), e.getMessage());
}
try {
orderAsyncProducer.sendCloudPrint(order.getId(), "ACCEPT_ORDER");
} catch (Exception e) {
log.warn("商家自配送订单云打印任务发送失败 orderId={}: {}", order.getId(), e.getMessage());
}
}
private void notifyOrScheduleStorePickupMake(MallOrder order) {
if (order == null || !Integer.valueOf(DELIVERY_TYPE_SELF).equals(order.getDeliveryType())) {
return;
}
if (Integer.valueOf(1).equals(order.getUserRequireMake())) {
notifyAndPrintStorePickupMake(order, "SHOP_INSTANT_MAKE");
triggerShopCookTimeoutEvent(order);
return;
}
if (order.getUserRequireMakeTime() == null) {
return;
}
long delayMillis = order.getUserRequireMakeTime().getTime()
- STORE_PICKUP_NOTIFY_BEFORE_MILLIS
- System.currentTimeMillis();
if (delayMillis <= 0) {
notifyAndPrintStorePickupMake(order, "SHOP_APPOINTMENT_MAKE");
triggerShopCookTimeoutEvent(order);
return;
}
orderAsyncProducer.sendDelayMessage(order.getId(), DELAY_TYPE_STORE_PICKUP_COOK_NOTIFY, delayMillis);
}
private void notifyAndPrintStorePickupMake(MallOrder order, String printReason) {
try {
Shop shop = getShopFromCache(order.getRegionId(), order.getShopId());
if (shop != null && StringUtils.isNotBlank(shop.getClientId())) {
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的到店订单", order.getId());
}
} catch (Exception e) {
log.warn("到店订单推送失败 orderId={}: {}", order.getId(), e.getMessage());
}
orderAsyncProducer.sendCloudPrint(order.getId(), printReason);
}
private void autoAcceptShopDeliveryOrder(MallOrder order, MallDeliveryOrder delivery) {

64
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/serviceimpl/mybatis/MallOrderServiceImpl.java

@ -82,8 +82,10 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
private static final int REFUND_STATUS_AFTER_SALE_AGREED = 4;//同意售后
private static final String DELAY_TYPE_ORDER_PAY_TIMEOUT = "Order_Pay_Timeout_1h";
private static final String DELAY_TYPE_GROUP_VIRTUAL_FORM = "Group_Virtual_Form_5m";
private static final String DELAY_TYPE_STORE_PICKUP_COOK_NOTIFY = "Store_Pickup_Cook_Notify";
private static final long ORDER_PAY_TIMEOUT_DELAY_MILLIS = 60 * 60 * 1000L;
private static final long GROUP_VIRTUAL_FORM_DELAY_MILLIS = 5 * 60 * 1000L;
private static final long STORE_PICKUP_NOTIFY_BEFORE_MILLIS = 30 * 60 * 1000L;
// 配送方式常量
private static final int DELIVERY_TYPE_EXPRESS = 1; // 外卖
@ -625,6 +627,10 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
if (headOrder == null) {
throw new RuntimeException("团长订单不存在");
}
order.setShopDelivery(headOrder.getShopDelivery());
order.setTransferDelivery(headOrder.getTransferDelivery());
order.setTransferAddressId(headOrder.getTransferAddressId());
order.setTransferAddressName(headOrder.getTransferAddressName());
order.setGetAreaId(headOrder.getGetAreaId());
order.setPutAreaId(headOrder.getPutAreaId());
order.setReceiverName(headOrder.getReceiverName());
@ -761,15 +767,7 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
MallOrderVO orderVO = buildVO(order, null, null, null);
orderVO.setStatus(STATUS_WAIT_PICKUP);
userPendingOrderCacheUtil.update(order.getUserId(), orderVO);
if(order.getUserRequireMake() != null && order.getUserRequireMake() == 1){
Shop shop = getShopFromCache(order.getRegionId(), order.getShopId());
if (shop != null && StringUtils.isNotBlank(shop.getClientId())) {
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的到店订单",orderId);
}
orderAsyncProducer.sendCloudPrint(orderId, "SHOP_INSTANT_MAKE");
// 触发商家出餐超时监听
triggerShopCookTimeoutEvent(orderId);
}
notifyOrScheduleStorePickupMake(order);
}
} else if (order.getOrderType() == ORDER_TYPE_GROUP || order.getOrderType() == ORDER_TYPE_FACETOFACE) {
/* // 查找属于该订单的拼团并检查成团条件
@ -1992,7 +1990,9 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
return null;
}
MallDeliveryOrder delivery = null;
if (Integer.valueOf(ORDER_TYPE_FACETOFACE).equals(order.getOrderType())) {
if (Integer.valueOf(DELIVERY_TYPE_SELF).equals(order.getDeliveryType())) {
return null;
} else if (Integer.valueOf(ORDER_TYPE_FACETOFACE).equals(order.getOrderType())) {
delivery = mallDeliveryOrderMapper.selectByGroupId(order.getId());
} else {
LambdaQueryWrapper<MallDeliveryOrder> dq = new LambdaQueryWrapper<>();
@ -2144,6 +2144,10 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
if(dto.getUserRequireMake() != null && dto.getUserRequireMake() == 1){
order.setUserRequireMake(dto.getUserRequireMake());
}
if (DELIVERY_TYPE_SELF == (dto.getDeliveryType() == null ? 0 : dto.getDeliveryType())
&& dto.getUserRequireMakeTime() != null) {
order.setUserRequireMakeTime(dto.getUserRequireMakeTime());
}
java.math.BigDecimal finalTotal = goodsAmount.add(deliveryFee).add(packageFee);
java.math.BigDecimal discount = java.math.BigDecimal.ZERO;
@ -2221,6 +2225,46 @@ public class MallOrderServiceImpl extends ServiceImpl<MallOrderMapper, MallOrder
} catch (Exception e) {
log.warn("商家自配送订单推送失败 orderId={}: {}", order.getId(), e.getMessage());
}
try {
orderAsyncProducer.sendCloudPrint(order.getId(), "ACCEPT_ORDER");
} catch (Exception e) {
log.warn("商家自配送订单云打印任务发送失败 orderId={}: {}", order.getId(), e.getMessage());
}
}
private void notifyOrScheduleStorePickupMake(MallOrder order) {
if (order == null || !Integer.valueOf(DELIVERY_TYPE_SELF).equals(order.getDeliveryType())) {
return;
}
if (Integer.valueOf(1).equals(order.getUserRequireMake())) {
notifyAndPrintStorePickupMake(order, "SHOP_INSTANT_MAKE");
triggerShopCookTimeoutEvent(order.getId());
return;
}
if (order.getUserRequireMakeTime() == null) {
return;
}
long delayMillis = order.getUserRequireMakeTime().getTime()
- STORE_PICKUP_NOTIFY_BEFORE_MILLIS
- System.currentTimeMillis();
if (delayMillis <= 0) {
notifyAndPrintStorePickupMake(order, "SHOP_APPOINTMENT_MAKE");
triggerShopCookTimeoutEvent(order.getId());
return;
}
orderAsyncProducer.sendDelayMessage(order.getId(), DELAY_TYPE_STORE_PICKUP_COOK_NOTIFY, delayMillis);
}
private void notifyAndPrintStorePickupMake(MallOrder order, String printReason) {
try {
Shop shop = getShopFromCache(order.getRegionId(), order.getShopId());
if (shop != null && StringUtils.isNotBlank(shop.getClientId())) {
jPushService.sendPushNotification(shop.getClientId(), "您有一笔新的到店订单", order.getId());
}
} catch (Exception e) {
log.warn("到店订单推送失败 orderId={}: {}", order.getId(), e.getMessage());
}
orderAsyncProducer.sendCloudPrint(order.getId(), printReason);
}
private void autoAcceptShopDeliveryOrder(MallOrder order, MallDeliveryOrder deliveryOrder) {

58
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/DaQuReceiptRenderUtil.java

@ -13,6 +13,7 @@ public final class DaQuReceiptRenderUtil {
private static final String LINE = "--------------------------------";
private static final String TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
private static final String APPOINTMENT_TIME_PATTERN = "yyyy-MM-dd HH:mm";
private static final String TARGET_SOCIAL_DELIVERY_REGION_ID = "2110300467664916480";
private DaQuReceiptRenderUtil() {
}
@ -25,10 +26,14 @@ public final class DaQuReceiptRenderUtil {
boolean forcedOrderPrint = isOrderEventPrint(printReason);
boolean scanVerifyPrint = isScanVerifyPrint(printReason);
boolean hasRefund = refundPrint && refunds != null && !refunds.isEmpty();
boolean targetSocialDeliveryOrder = isTargetSocialDeliveryOrder(order, delivery);
centerLarge(sb, orderNo(order));
centerLarge(sb, orderTypeText(order, delivery, refundPrint, forcedOrderPrint, scanVerifyPrint));
if (delivery != null && Integer.valueOf(1).equals(delivery.getAppointmentDelivery())) {
if (isSelfPickupAppointment(order)) {
largeLeft(sb, "实际取餐时间:");
largeLeft(sb, formatAppointmentTime(order.getUserRequireMakeTime()));
} else if (delivery != null && Integer.valueOf(1).equals(delivery.getAppointmentDelivery())) {
largeLeft(sb, "要求送达时间:");
largeLeft(sb, formatAppointmentTime(delivery.getMustFinishTime()));
}
@ -38,14 +43,14 @@ public final class DaQuReceiptRenderUtil {
left(sb, defaultString(order.getShopName()));
left(sb, "下单时间:" + formatTime(order.getCreateTime()));
if (!hasRefund) {
if (Integer.valueOf(1).equals(order.getDeliveryType()) && !Integer.valueOf(1).equals(delivery.getAppointmentDelivery())) {
if (Integer.valueOf(1).equals(order.getDeliveryType()) && (delivery == null || !Integer.valueOf(1).equals(delivery.getAppointmentDelivery()))) {
left(sb, "预计送达时间:" + formatTime(delivery == null ? null : delivery.getMustFinishTime()));
} else if (Integer.valueOf(1).equals(order.getUserRequireMake())) {
left(sb, "核销时间:" + formatTime(order.getCreateTime()));
} else if (Integer.valueOf(2).equals(order.getDeliveryType()) && Integer.valueOf(1).equals(order.getUserRequireMake())) {
left(sb, "出餐方式:立即出餐");
}
} else {
if (Integer.valueOf(1).equals(order.getUserRequireMake()) && Integer.valueOf(2).equals(order.getDeliveryType())) {
left(sb, "核销时间:" + formatTime(order.getCreateTime()));
left(sb, "出餐方式:立即出餐");
}
left(sb, "申请退款时间:" + formatTime(refunds.get(0).getCreateTime()));
}
@ -54,9 +59,17 @@ public final class DaQuReceiptRenderUtil {
if (shouldPrintDeliveryAddress(order, refundPrint, forcedOrderPrint)) {
largeLeft(sb, delivery == null ? "" : delivery.getReceiverName());
}
left(sb, "联系电话: " + maskPhoneLastFour(order.getReceiverPhone()));
if (targetSocialDeliveryOrder) {
largeLeft(sb, "联系电话: " + maskPhoneLastFour(order.getReceiverPhone()));
} else {
left(sb, "联系电话: " + maskPhoneLastFour(order.getReceiverPhone()));
}
if (shouldPrintDeliveryAddress(order, refundPrint, forcedOrderPrint)) {
largeLeft(sb, "地址:" + (delivery == null ? "" : delivery.getReceiverAddress()));
if (targetSocialDeliveryOrder) {
left(sb, "地址:" + (delivery == null ? "" : delivery.getReceiverAddress()));
} else {
largeLeft(sb, "地址:" + (delivery == null ? "" : delivery.getReceiverAddress()));
}
}
left(sb, "顾客电话已被隐藏,您可登录商家端或骑手端查看");
separator(sb);
@ -65,7 +78,7 @@ public final class DaQuReceiptRenderUtil {
for (MallOrderGoods goods : order.getGoodsList()) {
largeLeft(sb, defaultString(goods.getProductName()));
if (StringUtils.contains(goods.getSpecs(), ",")) {
left(sb, delNode(goods.getSpecs()));
boldLeft(sb, delNode(goods.getSpecs()));
}
largeLeft(sb, "¥" + amount(goods.getPrice()) + " X" + safeQuantity(goods.getQuantity()));
}
@ -114,7 +127,7 @@ public final class DaQuReceiptRenderUtil {
for (MallReturnOrderGoods goods : refund.getItems()) {
largeLeft(sb, defaultString(goods.getProductName()));
if (StringUtils.contains(goods.getSpecs(), ",")) {
left(sb, delNode(goods.getSpecs()));
boldLeft(sb, delNode(goods.getSpecs()));
}
largeLeft(sb, "¥" + amount(goods.getPrice()) + " X" + safeQuantity(goods.getQuantity()));
}
@ -136,6 +149,14 @@ public final class DaQuReceiptRenderUtil {
&& !Integer.valueOf(12).equals(status);
}
private static boolean isTargetSocialDeliveryOrder(MallOrderVO order, MallDeliveryOrder delivery) {
if (order == null || !Integer.valueOf(1).equals(order.getDeliveryType())) {
return false;
}
return TARGET_SOCIAL_DELIVERY_REGION_ID.equals(order.getRegionId())
|| (delivery != null && TARGET_SOCIAL_DELIVERY_REGION_ID.equals(delivery.getRegionId()));
}
private static String orderNo(MallOrderVO order) {
MallDeliveryOrder delivery = order.getDeliveryInfo();
if (isFaceToFaceDelivery(order)
@ -148,6 +169,9 @@ public final class DaQuReceiptRenderUtil {
private static String orderTypeText(MallOrderVO order, MallDeliveryOrder delivery, boolean refundPrint, boolean forcedOrderPrint, boolean scanVerifyPrint) {
Integer status = order.getStatus();
if (isSelfPickupAppointment(order) && !refundPrint) {
return "预约到店";
}
if (delivery != null && Integer.valueOf(1).equals(delivery.getAppointmentDelivery())
&& !refundPrint) {
return "预约单";
@ -167,7 +191,8 @@ public final class DaQuReceiptRenderUtil {
return "申请退款";
}
if (Integer.valueOf(3).equals(status) && Integer.valueOf(2).equals(order.getDeliveryType())
&& !Integer.valueOf(1).equals(order.getUserRequireMake())) {
&& !Integer.valueOf(1).equals(order.getUserRequireMake())
&& !isSelfPickupAppointment(order)) {
return "待消费";
}
if (scanVerifyPrint) {
@ -211,6 +236,12 @@ public final class DaQuReceiptRenderUtil {
&& Integer.valueOf(3).equals(order.getOrderType());
}
private static boolean isSelfPickupAppointment(MallOrderVO order) {
return order != null
&& Integer.valueOf(2).equals(order.getDeliveryType())
&& order.getUserRequireMakeTime() != null;
}
private static String amountLabel(MallOrderVO order, boolean hasRefund) {
if (hasRefund && !Integer.valueOf(2).equals(order.getDeliveryType())) {
return "实付金额:";
@ -220,7 +251,8 @@ public final class DaQuReceiptRenderUtil {
private static boolean isOrderEventPrint(String printReason) {
return StringUtils.containsIgnoreCase(printReason, "ACCEPT_ORDER")
|| StringUtils.containsIgnoreCase(printReason, "SHOP_INSTANT_MAKE");
|| StringUtils.containsIgnoreCase(printReason, "SHOP_INSTANT_MAKE")
|| StringUtils.containsIgnoreCase(printReason, "SHOP_APPOINTMENT_MAKE");
}
private static String refundReason(MallRefundRecord refund) {
@ -268,6 +300,10 @@ public final class DaQuReceiptRenderUtil {
sb.append("<LEFT><FONT bolder=0 height=2 width=2>").append(clean(text)).append("</FONT></LEFT><BR>");
}
private static void boldLeft(StringBuilder sb, String text) {
sb.append("<LEFT><FONT bolder=1 height=1 width=1>").append(clean(text)).append("</FONT></LEFT><BR>");
}
private static void center(StringBuilder sb, String text) {
sb.append("<C>").append(clean(text)).append("</C><BR>");
}

2
hiver-modules/hiver-mall/src/main/java/cc/hiver/mall/utils/cloudprint/CloudReceiptRenderUtil.java

@ -48,6 +48,7 @@ public final class CloudReceiptRenderUtil {
return normalizeDaQuContent(content)
.replaceAll("<C><FONT bolder=1 height=2 width=2>([\\s\\S]*?)</FONT></C><BR>", "<CB>$1</CB><BR>")
.replaceAll("<LEFT><FONT bolder=0 height=2 width=2>([\\s\\S]*?)</FONT></LEFT><BR>", "<B>$1</B><BR>")
.replaceAll("<LEFT><FONT bolder=1 height=1 width=1>([\\s\\S]*?)</FONT></LEFT><BR>", "<B>$1</B><BR>")
.replaceAll("<C>([\\s\\S]*?)</C><BR>", "<C>$1</C><BR>")
.replaceAll("<LEFT>([\\s\\S]*?)</LEFT><BR>", "$1<BR>");
}
@ -56,6 +57,7 @@ public final class CloudReceiptRenderUtil {
return normalizeDaQuContent(content)
.replaceAll("<C><FONT bolder=1 height=2 width=2>([\\s\\S]*?)</FONT></C><BR>", "<center><FS2>$1</FS2></center>\n")
.replaceAll("<LEFT><FONT bolder=0 height=2 width=2>([\\s\\S]*?)</FONT></LEFT><BR>", "<FS2>$1</FS2>\n")
.replaceAll("<LEFT><FONT bolder=1 height=1 width=1>([\\s\\S]*?)</FONT></LEFT><BR>", "<B>$1</B>\n")
.replaceAll("<C>([\\s\\S]*?)</C><BR>", "<center>$1</center>\n")
.replaceAll("<LEFT>([\\s\\S]*?)</LEFT><BR>", "$1\n")
.replace("<BR>", "\n");

2
hiver-modules/hiver-mall/src/main/resources/db/product_more_buy_product_ids.sql

@ -0,0 +1,2 @@
ALTER TABLE `t_product`
ADD COLUMN `more_buy_product_ids` varchar(2000) DEFAULT NULL COMMENT '可搭配商品ID,多个用逗号分隔' AFTER `is_more_buy`;

2
hiver-modules/hiver-mall/src/main/resources/db/shop_area_campus_text_enabled.sql

@ -0,0 +1,2 @@
ALTER TABLE `t_shop_area`
ADD COLUMN `campus_text_enabled` int(11) NOT NULL DEFAULT 0 COMMENT '社会区域文案是否按照校园显示:1开启,0关闭';

13
hiver-modules/hiver-mall/src/main/resources/mapper/ProductMapper.xml

@ -39,6 +39,7 @@
<result column="start_pay_num" jdbcType="INTEGER" property="startPayNum"/>
<result column="lunch_box" jdbcType="DECIMAL" property="lunchBox"/>
<result column="is_more_buy" jdbcType="INTEGER" property="isMoreBuy"/>
<result column="more_buy_product_ids" jdbcType="VARCHAR" property="moreBuyProductIds"/>
</resultMap>
<sql id="Example_Where_Clause">
<where>
@ -105,7 +106,7 @@
shop_id, category_id,attr_id, attribute_list, supplier_id,supplier_name, product_sn, barcode, price, purchase_price,commission,
wholesale_price, product_picture, product_video, product_intro, sales_week, print_barcode,
tail_warn,in_storage_status,customer_category_rule, attribute_list_price, is_push,
is_must, order_filed, sell_begin_time, sell_end_time, start_pay_num, lunch_box, is_more_buy
is_must, order_filed, sell_begin_time, sell_end_time, start_pay_num, lunch_box, is_more_buy, more_buy_product_ids
</sql>
<select id="selectByExample" parameterType="cc.hiver.mall.entity.ProductExample" resultMap="BaseResultMap">
select
@ -148,7 +149,7 @@
product_video, product_intro, sales_week,
print_barcode, tail_warn,in_storage_status,customer_category_rule,
attribute_list_price,is_push,is_must,order_filed,sell_begin_time, sell_end_time
, start_pay_num, lunch_box,is_more_buy)
, start_pay_num, lunch_box,is_more_buy,more_buy_product_ids)
values (#{id,jdbcType=VARCHAR}, #{createBy,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP},
#{delFlag,jdbcType=INTEGER}, #{updateBy,jdbcType=VARCHAR}, #{updateTime,jdbcType=TIMESTAMP},
#{productName,jdbcType=VARCHAR}, #{unit,jdbcType=VARCHAR}, #{shopId,jdbcType=VARCHAR},
@ -161,7 +162,7 @@
#{customerCategoryRule,jdbcType=VARCHAR},#{attributeListPrice,jdbcType=VARCHAR},
#{isPush,jdbcType=INTEGER}, #{isMust,jdbcType=INTEGER},
#{orderFiled,jdbcType=INTEGER},#{sellBeginTime,jdbcType=VARCHAR},
#{sellEndTime,jdbcType=VARCHAR},#{startPayNum,jdbcType=INTEGER}, #{lunchBox,jdbcType=DECIMAL},#{isMoreBuy,jdbcType=INTEGER})
#{sellEndTime,jdbcType=VARCHAR},#{startPayNum,jdbcType=INTEGER}, #{lunchBox,jdbcType=DECIMAL},#{isMoreBuy,jdbcType=INTEGER},#{moreBuyProductIds,jdbcType=VARCHAR})
</insert>
<insert id="insertSelective" parameterType="cc.hiver.mall.entity.Product">
insert into t_product
@ -697,7 +698,8 @@
sell_end_time = #{sellEndTime,jdbcType=VARCHAR},
start_pay_num = #{startPayNum,jdbcType=INTEGER},
lunch_box = #{lunchBox,jdbcType=DECIMAL},
is_more_buy = #{isMoreBuy,jdbcType=INTEGER}
is_more_buy = #{isMoreBuy,jdbcType=INTEGER},
more_buy_product_ids = #{moreBuyProductIds,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
@ -740,7 +742,8 @@
t.sell_end_time,
t.start_pay_num,
t.lunch_box,
t.is_more_buy
t.is_more_buy,
t.more_buy_product_ids
FROM t_product t
LEFT JOIN t_product_category pc ON t.category_id = pc.id
<where>

10
hiver-modules/hiver-social/src/main/java/cc/hiver/social/controller/WechatController.java

@ -178,8 +178,14 @@ public class WechatController {
u.setInviteDeviceId(deviceId);
}
userService.update(u);
InviteRewardResult rewardResult = inviteRewardService.rewardAfterPhoneBound(
u, phoneNumber, inviterId, regionId, deviceId, lat, lng, firstPhoneBind);
InviteRewardResult rewardResult = InviteRewardResult.skipped("未触发拉新奖励");
try {
rewardResult = inviteRewardService.rewardAfterPhoneBound(
u, phoneNumber, inviterId, regionId, deviceId, lat, lng, firstPhoneBind);
} catch (Exception rewardException) {
log.warn("拉新奖励处理失败但不影响手机号绑定: userId={}, inviterId={}, regionId={}",
u.getId(), inviterId, regionId, rewardException);
}
// 删除缓存
redisTemplate.delete(key);
//User newUser = userService.findByMobile(phoneNumber);

Loading…
Cancel
Save