v1.0.30 #40
+16
-1
@@ -59,6 +59,7 @@ public class AttachmentVariantServiceImplement implements AttachmentVariantServi
|
|||||||
private static final long THUMB_CACHE_TTL = Time.D * 7;
|
private static final long THUMB_CACHE_TTL = Time.D * 7;
|
||||||
private static final long THUMB_LOCK_TTL = Time.M * 10;
|
private static final long THUMB_LOCK_TTL = Time.M * 10;
|
||||||
private static final double THUMB_TARGET_SECONDS = 2;
|
private static final double THUMB_TARGET_SECONDS = 2;
|
||||||
|
private static final int VARIANT_NAME_MAX_LENGTH = 255;
|
||||||
private static final String THUMB_OUTPUT_FORMAT = "png";
|
private static final String THUMB_OUTPUT_FORMAT = "png";
|
||||||
private static final String THUMB_ALGORITHM_VERSION = "v3";
|
private static final String THUMB_ALGORITHM_VERSION = "v3";
|
||||||
private static final String THUMB_LOCK_KEY_PREFIX = "ATTACHMENT:THUMB:LOCK:";
|
private static final String THUMB_LOCK_KEY_PREFIX = "ATTACHMENT:THUMB:LOCK:";
|
||||||
@@ -158,7 +159,7 @@ public class AttachmentVariantServiceImplement implements AttachmentVariantServi
|
|||||||
thumbFile = createThumbFile(source, requestWidth, requestHeight, fitMode, isImage);
|
thumbFile = createThumbFile(source, requestWidth, requestHeight, fitMode, isImage);
|
||||||
variant = new AttachmentVariant();
|
variant = new AttachmentVariant();
|
||||||
variant.setId(UUID.randomUUID().toString());
|
variant.setId(UUID.randomUUID().toString());
|
||||||
variant.setName(Network.simpleURIFileName(source.getName()) + "." + THUMB_OUTPUT_FORMAT);
|
variant.setName(buildVariantName(source.getName()));
|
||||||
variant.setMimeType("image/" + THUMB_OUTPUT_FORMAT);
|
variant.setMimeType("image/" + THUMB_OUTPUT_FORMAT);
|
||||||
long expireAt = Time.now() + THUMB_CACHE_TTL;
|
long expireAt = Time.now() + THUMB_CACHE_TTL;
|
||||||
variant.setSourceAttachmentId(source.getId());
|
variant.setSourceAttachmentId(source.getId());
|
||||||
@@ -257,6 +258,20 @@ public class AttachmentVariantServiceImplement implements AttachmentVariantServi
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 构建不超过数据库字段长度的变体名称
|
||||||
|
///
|
||||||
|
/// @param sourceName 源附件名称
|
||||||
|
/// @return 变体名称
|
||||||
|
private String buildVariantName(String sourceName) {
|
||||||
|
String suffix = "." + THUMB_OUTPUT_FORMAT;
|
||||||
|
String baseName = Network.simpleURIFileName(sourceName);
|
||||||
|
int maxBaseLength = VARIANT_NAME_MAX_LENGTH - suffix.length();
|
||||||
|
if (maxBaseLength < baseName.codePointCount(0, baseName.length())) {
|
||||||
|
baseName = baseName.substring(0, baseName.offsetByCodePoints(0, maxBaseLength));
|
||||||
|
}
|
||||||
|
return baseName + suffix;
|
||||||
|
}
|
||||||
|
|
||||||
private File createThumbFile(
|
private File createThumbFile(
|
||||||
Attachment source,
|
Attachment source,
|
||||||
Integer requestWidth,
|
Integer requestWidth,
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ public enum GaoPermissionCode implements BuiltinPermissionCode {
|
|||||||
|
|
||||||
CUSTOMER_PACKAGE_CANCEL("CUSTOMER_PACKAGE:CANCEL", "客户套餐取消", true, true),
|
CUSTOMER_PACKAGE_CANCEL("CUSTOMER_PACKAGE:CANCEL", "客户套餐取消", true, true),
|
||||||
|
|
||||||
CUSTOMER_PACKAGE_PRICE_OVERRIDE("CUSTOMER_PACKAGE:PRICE_OVERRIDE", "客户套餐成交价和产品定制", true, true),
|
CUSTOMER_PACKAGE_PRICE_OVERRIDE("CUSTOMER_PACKAGE:PRICE_OVERRIDE", "客户套餐成交价和权益配额调整", true, true),
|
||||||
|
|
||||||
PACKAGE_DELIVERY_CREATE("PACKAGE_DELIVERY:CREATE", "套餐发放创建", true, true),
|
PACKAGE_DELIVERY_CREATE("PACKAGE_DELIVERY:CREATE", "套餐发放创建", true, true),
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public enum GaoRoleCode implements BuiltinRoleCode {
|
|||||||
GLOBAL_MANAGER("门店管理", null),
|
GLOBAL_MANAGER("门店管理", null),
|
||||||
|
|
||||||
/// 店长
|
/// 店长
|
||||||
STORE_MANAGER("店长", GLOBAL_MANAGER.name());
|
STORE_MANAGER("店长", null);
|
||||||
|
|
||||||
final String defaultName;
|
final String defaultName;
|
||||||
final String parentCode;
|
final String parentCode;
|
||||||
|
|||||||
@@ -4,7 +4,10 @@ import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
|||||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoEvent;
|
import com.imyeyu.api.modules.gao.entity.GaoEvent;
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoEventOptionGroup;
|
import com.imyeyu.api.modules.gao.entity.GaoEventOptionGroup;
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoPackageConfig;
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoPackageConfigItem;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoEventService;
|
import com.imyeyu.api.modules.gao.service.GaoEventService;
|
||||||
|
import com.imyeyu.api.modules.gao.service.GaoPackageConfigService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoStoreScopeService;
|
import com.imyeyu.api.modules.gao.service.GaoStoreScopeService;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
@@ -32,6 +35,7 @@ import java.util.Map;
|
|||||||
public class GaoEventController {
|
public class GaoEventController {
|
||||||
|
|
||||||
private final GaoEventService service;
|
private final GaoEventService service;
|
||||||
|
private final GaoPackageConfigService packageConfigService;
|
||||||
private final GaoStoreScopeService storeScopeService;
|
private final GaoStoreScopeService storeScopeService;
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@@ -69,15 +73,38 @@ public class GaoEventController {
|
|||||||
event.setRoleCodeList(roleMap.get(event.getId()));
|
event.setRoleCodeList(roleMap.get(event.getId()));
|
||||||
}
|
}
|
||||||
service.attachOptionGroupList(result.getList());
|
service.attachOptionGroupList(result.getList());
|
||||||
|
attachPackageConfig(result.getList());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void attachPackageConfig(List<GaoEvent> eventList) {
|
||||||
|
List<String> packageConfigIdList = eventList.stream()
|
||||||
|
.map(GaoEvent::getPackageConfigId)
|
||||||
|
.filter(TimiJava::isNotEmpty)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
if (packageConfigIdList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, GaoPackageConfig> packageConfigMap = packageConfigService.mapByIdList(packageConfigIdList);
|
||||||
|
Map<String, List<GaoPackageConfigItem>> itemMap = packageConfigService.mapItemListByPackageConfigIdList(packageConfigIdList);
|
||||||
|
for (GaoEvent event : eventList) {
|
||||||
|
GaoPackageConfig packageConfig = packageConfigMap.get(event.getPackageConfigId());
|
||||||
|
if (packageConfig != null) {
|
||||||
|
packageConfig.setItemList(itemMap.getOrDefault(packageConfig.getId(), List.of()));
|
||||||
|
event.setPackageConfig(packageConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.EVENT_READ)
|
@RequireGaoPermission(GaoPermissionCode.EVENT_READ)
|
||||||
@PostMapping("/list/valid")
|
@PostMapping("/list/valid")
|
||||||
public List<GaoEvent> listValid(@RequestParam String storeId) {
|
public List<GaoEvent> listValid(@RequestParam String storeId) {
|
||||||
return service.listValid(storeScopeService.resolveStoreId(storeId));
|
List<GaoEvent> result = service.listValid(storeScopeService.resolveStoreId(storeId));
|
||||||
|
attachPackageConfig(result);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@@ -90,6 +117,7 @@ public class GaoEventController {
|
|||||||
storeScopeService.checkStoreId(event.getStoreId());
|
storeScopeService.checkStoreId(event.getStoreId());
|
||||||
event.setRoleCodeList(service.listRoleCode(event.getId()));
|
event.setRoleCodeList(service.listRoleCode(event.getId()));
|
||||||
service.attachOptionGroupList(List.of(event));
|
service.attachOptionGroupList(List.of(event));
|
||||||
|
attachPackageConfig(List.of(event));
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ import com.imyeyu.api.modules.gao.service.GaoEventRecordService;
|
|||||||
import com.imyeyu.api.modules.gao.service.GaoEventService;
|
import com.imyeyu.api.modules.gao.service.GaoEventService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoStoreScopeService;
|
import com.imyeyu.api.modules.gao.service.GaoStoreScopeService;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerEventRankView;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerEventRankView;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoEventOptionStatView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoEventRecordPage;
|
import com.imyeyu.api.modules.gao.vo.GaoEventRecordPage;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoEventRecordPageResult;
|
import com.imyeyu.api.modules.gao.vo.GaoEventRecordPageResult;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoEventRecordRankPage;
|
import com.imyeyu.api.modules.gao.vo.GaoEventRecordRankPage;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoEventOptionStatView;
|
|
||||||
import com.imyeyu.api.modules.user.service.UserService;
|
import com.imyeyu.api.modules.user.service.UserService;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
@@ -114,6 +114,7 @@ public class GaoEventRecordController {
|
|||||||
record.setEvent(eventService.get(record.getEventId()));
|
record.setEvent(eventService.get(record.getEventId()));
|
||||||
eventService.attachOptionGroupList(List.of(record.getEvent()));
|
eventService.attachOptionGroupList(List.of(record.getEvent()));
|
||||||
record.setOperator(userService.get(record.getOperatorUserId()));
|
record.setOperator(userService.get(record.getOperatorUserId()));
|
||||||
|
record.setUpdater(userService.get(record.getUpdatedBy()));
|
||||||
if (record.getVerifierUserId() != null) {
|
if (record.getVerifierUserId() != null) {
|
||||||
record.setVerifier(userService.get(record.getVerifierUserId()));
|
record.setVerifier(userService.get(record.getVerifierUserId()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,6 +106,13 @@ public class GaoEvent extends UUIDEntity {
|
|||||||
/// 业务类型
|
/// 业务类型
|
||||||
private BizType bizType;
|
private BizType bizType;
|
||||||
|
|
||||||
|
/// 购买套餐事件绑定的套餐配置 ID
|
||||||
|
private String packageConfigId;
|
||||||
|
|
||||||
|
/// 购买套餐事件绑定的套餐配置
|
||||||
|
@Transient
|
||||||
|
private GaoPackageConfig packageConfig;
|
||||||
|
|
||||||
/// 登记事件名称
|
/// 登记事件名称
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ public class GaoEventRecord extends UUIDEntity {
|
|||||||
/// 营业日递增序号
|
/// 营业日递增序号
|
||||||
private Long businessDayNo;
|
private Long businessDayNo;
|
||||||
|
|
||||||
|
/// 最后修改用户 ID
|
||||||
|
private String updatedBy;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private GaoCustomer customer;
|
private GaoCustomer customer;
|
||||||
|
|
||||||
@@ -99,6 +102,10 @@ public class GaoEventRecord extends UUIDEntity {
|
|||||||
@Transient
|
@Transient
|
||||||
private User verifier;
|
private User verifier;
|
||||||
|
|
||||||
|
/// 最后修改用户
|
||||||
|
@Transient
|
||||||
|
private User updater;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private List<Attachment> attachmentList;
|
private List<Attachment> attachmentList;
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.imyeyu.api.modules.gao.entity.GaoEvent;
|
|||||||
import com.imyeyu.spring.bean.Page;
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
import org.apache.ibatis.annotations.SelectProvider;
|
import org.apache.ibatis.annotations.SelectProvider;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -25,4 +26,7 @@ public interface GaoEventMapper extends BaseMapper<GaoEvent, String> {
|
|||||||
List<GaoEvent> selectByIdList(Collection<String> idList);
|
List<GaoEvent> selectByIdList(Collection<String> idList);
|
||||||
|
|
||||||
List<GaoEvent> selectValidList(@Param("storeId") String storeId, @Param("now") Long now);
|
List<GaoEvent> selectValidList(@Param("storeId") String storeId, @Param("now") Long now);
|
||||||
|
|
||||||
|
@Select("SELECT COUNT(*) FROM `gao_event` WHERE `package_config_id` = #{packageConfigId} AND `deleted_at` IS NULL")
|
||||||
|
long countByPackageConfigId(String packageConfigId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import com.imyeyu.api.modules.gao.vo.GaoEventOptionStatView;
|
|||||||
import com.imyeyu.api.modules.gao.vo.GaoStoreChartReq;
|
import com.imyeyu.api.modules.gao.vo.GaoStoreChartReq;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -21,6 +22,13 @@ import java.util.List;
|
|||||||
/// @since 2026-07-27 14:11
|
/// @since 2026-07-27 14:11
|
||||||
public interface GaoEventRecordMapper extends BaseMapper<GaoEventRecord, String> {
|
public interface GaoEventRecordMapper extends BaseMapper<GaoEventRecord, String> {
|
||||||
|
|
||||||
|
/// 查询事件登记记录数量
|
||||||
|
///
|
||||||
|
/// @param eventId 事件 ID
|
||||||
|
/// @return 登记记录数量
|
||||||
|
@Select("SELECT COUNT(*) FROM `gao_event_record` WHERE `event_id` = #{eventId} AND `deleted_at` IS NULL")
|
||||||
|
long countByEventId(String eventId);
|
||||||
|
|
||||||
Long count(String storeId, String customerId, String eventId, Long beginAt, Long endAt);
|
Long count(String storeId, String customerId, String eventId, Long beginAt, Long endAt);
|
||||||
|
|
||||||
/// 查询事件中已携带数值的登记记录数量
|
/// 查询事件中已携带数值的登记记录数量
|
||||||
@@ -50,8 +58,9 @@ public interface GaoEventRecordMapper extends BaseMapper<GaoEventRecord, String>
|
|||||||
/// @param id 登记记录 ID
|
/// @param id 登记记录 ID
|
||||||
/// @param verifierUserId 核销用户 ID
|
/// @param verifierUserId 核销用户 ID
|
||||||
/// @param verifiedAt 核销时间
|
/// @param verifiedAt 核销时间
|
||||||
|
/// @param updatedBy 最后修改用户 ID
|
||||||
/// @return 更新行数
|
/// @return 更新行数
|
||||||
int verify(@Param("id") String id, @Param("verifierUserId") String verifierUserId, @Param("verifiedAt") Long verifiedAt);
|
int verify(@Param("id") String id, @Param("verifierUserId") String verifierUserId, @Param("verifiedAt") Long verifiedAt, @Param("updatedBy") String updatedBy);
|
||||||
|
|
||||||
/// 按门店和登记日期统计登记记录数
|
/// 按门店和登记日期统计登记记录数
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -22,6 +22,12 @@ public interface GaoPackageConfigService extends BaseService<GaoPackageConfig, S
|
|||||||
/// 查询有效可购买套餐
|
/// 查询有效可购买套餐
|
||||||
List<GaoPackageConfig> listValid(String storeId);
|
List<GaoPackageConfig> listValid(String storeId);
|
||||||
|
|
||||||
|
/// 批量查询套餐配置
|
||||||
|
///
|
||||||
|
/// @param idList 套餐配置 ID 列表
|
||||||
|
/// @return 按套餐配置 ID 映射的配置
|
||||||
|
Map<String, GaoPackageConfig> mapByIdList(Collection<String> idList);
|
||||||
|
|
||||||
/// 查询套餐配置产品明细
|
/// 查询套餐配置产品明细
|
||||||
///
|
///
|
||||||
/// @param packageConfigId 套餐配置 ID
|
/// @param packageConfigId 套餐配置 ID
|
||||||
|
|||||||
+50
-32
@@ -171,23 +171,25 @@ public class GaoCustomerPackageServiceImplement extends AbstractEntityService<Ga
|
|||||||
TimiException.required(request, "not found purchase request");
|
TimiException.required(request, "not found purchase request");
|
||||||
TimiException.required(request.getRequestNo(), "not found requestNo");
|
TimiException.required(request.getRequestNo(), "not found requestNo");
|
||||||
request.setRequestNo(request.getRequestNo().trim());
|
request.setRequestNo(request.getRequestNo().trim());
|
||||||
TimiException.required(request.getPackageConfigId(), "not found packageConfigId");
|
|
||||||
TimiException.required(request.getEventId(), "not found eventId");
|
TimiException.required(request.getEventId(), "not found eventId");
|
||||||
TimiException.required(request.getCustomerId(), "not found customerId");
|
TimiException.required(request.getCustomerId(), "not found customerId");
|
||||||
TimiException.required(request.getSaleAmount(), "not found saleAmount");
|
|
||||||
TimiException.requiredTrue(0 <= request.getSaleAmount(), "成交价不能为负数");
|
|
||||||
|
|
||||||
GaoPackageConfig config = packageConfigService.get(request.getPackageConfigId());
|
GaoEvent event = validatePurchaseEvent(request.getEventId());
|
||||||
if (config == null) {
|
storeScopeService.checkStoreId(event.getStoreId());
|
||||||
GaoCustomerPackage existing = mapper.selectByRequestNoAnyStore(request.getRequestNo());
|
GaoPackageConfig config = packageConfigService.get(event.getPackageConfigId());
|
||||||
if (existing != null) {
|
TimiException.required(config, "购买事件绑定的套餐配置不存在");
|
||||||
storeScopeService.checkStoreId(existing.getStoreId());
|
TimiException.requiredTrue(event.getStoreId().equals(config.getStoreId()), "购买事件和套餐配置不属于同一门店");
|
||||||
verifyPurchaseIdempotency(existing, request);
|
List<GaoPackageConfigItem> configItemList = packageConfigService.listItemByPackageConfigId(config.getId());
|
||||||
return existing;
|
request.setSaleAmount(TimiJava.defaultIfNull(request.getSaleAmount(), config.getStandardAmount()));
|
||||||
|
TimiException.requiredTrue(0 <= request.getSaleAmount(), "成交价不能为负数");
|
||||||
|
if (request.getItemList() == null) {
|
||||||
|
request.setItemList(defaultPurchaseItems(configItemList));
|
||||||
}
|
}
|
||||||
}
|
List<GaoCustomerPackagePurchaseItem> itemList = new java.util.ArrayList<>(request.getItemList());
|
||||||
TimiException.required(config, "not found package config");
|
verifyPurchaseItems(itemList);
|
||||||
storeScopeService.checkStoreId(config.getStoreId());
|
itemList.sort(java.util.Comparator.comparing(GaoCustomerPackagePurchaseItem::getSort));
|
||||||
|
request.setItemList(itemList);
|
||||||
|
|
||||||
GaoCustomerPackage existing = mapper.selectByRequestNo(config.getStoreId(), request.getRequestNo());
|
GaoCustomerPackage existing = mapper.selectByRequestNo(config.getStoreId(), request.getRequestNo());
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
verifyPurchaseIdempotency(existing, request);
|
verifyPurchaseIdempotency(existing, request);
|
||||||
@@ -199,17 +201,12 @@ public class GaoCustomerPackageServiceImplement extends AbstractEntityService<Ga
|
|||||||
TimiException.requiredTrue(config.getStatus() == GaoPackageConfig.Status.ACTIVE, "套餐配置不可购买");
|
TimiException.requiredTrue(config.getStatus() == GaoPackageConfig.Status.ACTIVE, "套餐配置不可购买");
|
||||||
TimiException.requiredTrue(config.getBeginAt() == null || config.getBeginAt() <= now, "套餐配置尚未生效");
|
TimiException.requiredTrue(config.getBeginAt() == null || config.getBeginAt() <= now, "套餐配置尚未生效");
|
||||||
TimiException.requiredTrue(config.getEndAt() == null || now <= config.getEndAt(), "套餐配置已过期");
|
TimiException.requiredTrue(config.getEndAt() == null || now <= config.getEndAt(), "套餐配置已过期");
|
||||||
List<GaoPackageConfigItem> configItemList = packageConfigService.listItemByPackageConfigId(config.getId());
|
|
||||||
GaoCustomer customer = validateCustomer(request.getCustomerId(), config.getStoreId());
|
GaoCustomer customer = validateCustomer(request.getCustomerId(), config.getStoreId());
|
||||||
GaoEvent event = validatePurchaseEvent(request.getEventId(), config.getStoreId());
|
verifySameStructureAsConfig(itemList, configItemList);
|
||||||
|
boolean canOverridePriceAndQuantity = permissionChecker.hasAny(ModuleCode.GAO, com.imyeyu.api.modules.gao.bean.GaoPermissionCode.CUSTOMER_PACKAGE_PRICE_OVERRIDE.getValue());
|
||||||
List<GaoCustomerPackagePurchaseItem> itemList = new java.util.ArrayList<>(TimiJava.defaultIfNull(request.getItemList(), List.of()));
|
if (!canOverridePriceAndQuantity) {
|
||||||
verifyPurchaseItems(itemList);
|
|
||||||
itemList.sort(java.util.Comparator.comparing(GaoCustomerPackagePurchaseItem::getSort));
|
|
||||||
boolean canOverride = permissionChecker.hasAny(ModuleCode.GAO, com.imyeyu.api.modules.gao.bean.GaoPermissionCode.CUSTOMER_PACKAGE_PRICE_OVERRIDE.getValue());
|
|
||||||
if (!canOverride) {
|
|
||||||
TimiException.requiredTrue(request.getSaleAmount().equals(config.getStandardAmount()), "普通员工不能修改套餐成交价");
|
TimiException.requiredTrue(request.getSaleAmount().equals(config.getStandardAmount()), "普通员工不能修改套餐成交价");
|
||||||
verifySameAsConfig(itemList, configItemList);
|
verifySameQuantityAsConfig(itemList, configItemList);
|
||||||
}
|
}
|
||||||
|
|
||||||
GaoEventRecord eventRecord = new GaoEventRecord();
|
GaoEventRecord eventRecord = new GaoEventRecord();
|
||||||
@@ -299,14 +296,26 @@ public class GaoCustomerPackageServiceImplement extends AbstractEntityService<Ga
|
|||||||
return customer;
|
return customer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private GaoEvent validatePurchaseEvent(String eventId, String storeId) {
|
private GaoEvent validatePurchaseEvent(String eventId) {
|
||||||
GaoEvent event = eventService.get(eventId);
|
GaoEvent event = eventService.get(eventId);
|
||||||
TimiException.required(event, "not found purchase event");
|
TimiException.required(event, "not found purchase event");
|
||||||
TimiException.requiredTrue(storeId.equals(event.getStoreId()), "购买事件和套餐不属于同一门店");
|
|
||||||
TimiException.requiredTrue(event.getBizType() == GaoEvent.BizType.PACKAGE_PURCHASE, "事件不是套餐购买事件");
|
TimiException.requiredTrue(event.getBizType() == GaoEvent.BizType.PACKAGE_PURCHASE, "事件不是套餐购买事件");
|
||||||
|
TimiException.required(event.getPackageConfigId(), "购买事件未绑定套餐配置");
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<GaoCustomerPackagePurchaseItem> defaultPurchaseItems(List<GaoPackageConfigItem> configItemList) {
|
||||||
|
return configItemList.stream().map(configItem -> {
|
||||||
|
GaoCustomerPackagePurchaseItem item = new GaoCustomerPackagePurchaseItem();
|
||||||
|
item.setProductName(configItem.getProductName());
|
||||||
|
item.setUnit(configItem.getUnit());
|
||||||
|
item.setTotalQuantity(configItem.getDefaultQuantity());
|
||||||
|
item.setSort(configItem.getSort());
|
||||||
|
item.setRemark(configItem.getRemark());
|
||||||
|
return item;
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
private void verifyPurchaseItems(List<GaoCustomerPackagePurchaseItem> itemList) {
|
private void verifyPurchaseItems(List<GaoCustomerPackagePurchaseItem> itemList) {
|
||||||
TimiException.requiredTrue(!itemList.isEmpty(), "购买套餐至少需要一个产品");
|
TimiException.requiredTrue(!itemList.isEmpty(), "购买套餐至少需要一个产品");
|
||||||
Set<String> keySet = new HashSet<>();
|
Set<String> keySet = new HashSet<>();
|
||||||
@@ -326,20 +335,27 @@ public class GaoCustomerPackageServiceImplement extends AbstractEntityService<Ga
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifySameAsConfig(List<GaoCustomerPackagePurchaseItem> itemList, List<GaoPackageConfigItem> configItemList) {
|
private void verifySameStructureAsConfig(List<GaoCustomerPackagePurchaseItem> itemList, List<GaoPackageConfigItem> configItemList) {
|
||||||
TimiException.requiredTrue(itemList.size() == configItemList.size(), "普通员工不能修改套餐产品明细");
|
TimiException.requiredTrue(itemList.size() == configItemList.size(), "套餐权益项目必须与事件绑定套餐一致");
|
||||||
Map<String, GaoCustomerPackagePurchaseItem> itemMap = itemList.stream().collect(Collectors.toMap(item -> item.getProductName() + "|" + item.getUnit(), Function.identity()));
|
Map<String, GaoCustomerPackagePurchaseItem> itemMap = itemList.stream().collect(Collectors.toMap(item -> item.getProductName() + "|" + item.getUnit(), Function.identity()));
|
||||||
for (GaoPackageConfigItem configItem : configItemList) {
|
for (GaoPackageConfigItem configItem : configItemList) {
|
||||||
GaoCustomerPackagePurchaseItem item = itemMap.get(configItem.getProductName() + "|" + configItem.getUnit());
|
GaoCustomerPackagePurchaseItem item = itemMap.get(configItem.getProductName() + "|" + configItem.getUnit());
|
||||||
TimiException.required(item, "普通员工不能修改套餐产品明细");
|
TimiException.required(item, "套餐权益项目必须与事件绑定套餐一致");
|
||||||
TimiException.requiredTrue(item.getTotalQuantity().compareTo(configItem.getDefaultQuantity()) == 0
|
TimiException.requiredTrue(item.getSort().equals(configItem.getSort())
|
||||||
&& item.getSort().equals(configItem.getSort()), "普通员工不能修改套餐产品明细");
|
&& sameText(item.getRemark(), configItem.getRemark()), "套餐权益项目的名称、单位、排序和备注不可修改");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifySameQuantityAsConfig(List<GaoCustomerPackagePurchaseItem> itemList, List<GaoPackageConfigItem> configItemList) {
|
||||||
|
Map<String, GaoCustomerPackagePurchaseItem> itemMap = itemList.stream().collect(Collectors.toMap(item -> item.getProductName() + "|" + item.getUnit(), Function.identity()));
|
||||||
|
for (GaoPackageConfigItem configItem : configItemList) {
|
||||||
|
GaoCustomerPackagePurchaseItem item = itemMap.get(configItem.getProductName() + "|" + configItem.getUnit());
|
||||||
|
TimiException.requiredTrue(item.getTotalQuantity().compareTo(configItem.getDefaultQuantity()) == 0, "普通员工不能修改套餐权益配额");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyPurchaseIdempotency(GaoCustomerPackage existing, GaoCustomerPackagePurchaseRequest request) {
|
private void verifyPurchaseIdempotency(GaoCustomerPackage existing, GaoCustomerPackagePurchaseRequest request) {
|
||||||
TimiException.requiredTrue(existing.getPackageConfigId().equals(request.getPackageConfigId())
|
TimiException.requiredTrue(existing.getCustomerId().equals(request.getCustomerId())
|
||||||
&& existing.getCustomerId().equals(request.getCustomerId())
|
|
||||||
&& existing.getSaleAmount().equals(request.getSaleAmount()), "requestNo 已被其他购买请求使用");
|
&& existing.getSaleAmount().equals(request.getSaleAmount()), "requestNo 已被其他购买请求使用");
|
||||||
GaoEventRecord eventRecord = eventRecordService.get(existing.getPurchaseEventRecordId());
|
GaoEventRecord eventRecord = eventRecordService.get(existing.getPurchaseEventRecordId());
|
||||||
TimiException.required(eventRecord, "购买事件登记不存在");
|
TimiException.required(eventRecord, "购买事件登记不存在");
|
||||||
@@ -354,7 +370,9 @@ public class GaoCustomerPackageServiceImplement extends AbstractEntityService<Ga
|
|||||||
for (GaoCustomerPackagePurchaseItem item : requestItemList) {
|
for (GaoCustomerPackagePurchaseItem item : requestItemList) {
|
||||||
GaoCustomerPackageItem existingItem = existingItemMap.get(item.getProductName() + "|" + item.getUnit());
|
GaoCustomerPackageItem existingItem = existingItemMap.get(item.getProductName() + "|" + item.getUnit());
|
||||||
TimiException.required(existingItem, "requestNo 对应购买请求内容不一致");
|
TimiException.required(existingItem, "requestNo 对应购买请求内容不一致");
|
||||||
TimiException.requiredTrue(existingItem.getTotalQuantity().compareTo(item.getTotalQuantity()) == 0 && existingItem.getSort().equals(item.getSort()), "requestNo 对应购买请求内容不一致");
|
TimiException.requiredTrue(existingItem.getTotalQuantity().compareTo(item.getTotalQuantity()) == 0
|
||||||
|
&& existingItem.getSort().equals(item.getSort())
|
||||||
|
&& sameText(existingItem.getRemark(), item.getRemark()), "requestNo 对应购买请求内容不一致");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -139,7 +139,8 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
GaoEventRecord record = get(id);
|
GaoEventRecord record = get(id);
|
||||||
TimiException.required(record, "not found event record");
|
TimiException.required(record, "not found event record");
|
||||||
TimiException.requiredTrue(record.getVerificationStatus() == GaoEventRecord.VerificationStatus.PENDING, "登记记录无需核销或已核销");
|
TimiException.requiredTrue(record.getVerificationStatus() == GaoEventRecord.VerificationStatus.PENDING, "登记记录无需核销或已核销");
|
||||||
int updated = mapper.verify(id, userLoginService.getRequireLoginUserId(), Time.now());
|
String loginUserId = userLoginService.getRequireLoginUserId();
|
||||||
|
int updated = mapper.verify(id, loginUserId, Time.now(), loginUserId);
|
||||||
TimiException.requiredTrue(0 < updated, "登记记录无需核销或已核销");
|
TimiException.requiredTrue(0 < updated, "登记记录无需核销或已核销");
|
||||||
logger.setLevel(Logger.Level.INFO);
|
logger.setLevel(Logger.Level.INFO);
|
||||||
logger.setResult(id);
|
logger.setResult(id);
|
||||||
@@ -175,7 +176,6 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
return createInternal(record, true);
|
return createInternal(record, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
|
||||||
private GaoEventRecord createInternal(GaoEventRecord record, boolean packagePurchase) {
|
private GaoEventRecord createInternal(GaoEventRecord record, boolean packagePurchase) {
|
||||||
TimiException.required(record, "not found record");
|
TimiException.required(record, "not found record");
|
||||||
|
|
||||||
@@ -224,6 +224,7 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
dbRecord.setStoreId(event.getStoreId());
|
dbRecord.setStoreId(event.getStoreId());
|
||||||
dbRecord.setEventId(record.getEventId());
|
dbRecord.setEventId(record.getEventId());
|
||||||
dbRecord.setOperatorUserId(loginUserId);
|
dbRecord.setOperatorUserId(loginUserId);
|
||||||
|
dbRecord.setUpdatedBy(loginUserId);
|
||||||
dbRecord.setRemark(record.getRemark());
|
dbRecord.setRemark(record.getRemark());
|
||||||
dbRecord.setRegisteredAt(registeredAt);
|
dbRecord.setRegisteredAt(registeredAt);
|
||||||
dbRecord.setRegisteredDateValue(registeredDateValue);
|
dbRecord.setRegisteredDateValue(registeredDateValue);
|
||||||
@@ -318,6 +319,7 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
verifyRecordAttachment(event, record.getAttachmentList());
|
verifyRecordAttachment(event, record.getAttachmentList());
|
||||||
checkEventPermission(event);
|
checkEventPermission(event);
|
||||||
dbRecord.setRemark(record.getRemark());
|
dbRecord.setRemark(record.getRemark());
|
||||||
|
dbRecord.setUpdatedBy(userLoginService.getRequireLoginUserId());
|
||||||
super.update(dbRecord);
|
super.update(dbRecord);
|
||||||
if (canonicalOptionList != null) {
|
if (canonicalOptionList != null) {
|
||||||
GaoEventRecordOption optionExample = new GaoEventRecordOption();
|
GaoEventRecordOption optionExample = new GaoEventRecordOption();
|
||||||
|
|||||||
+13
@@ -6,12 +6,14 @@ import com.imyeyu.api.modules.gao.entity.GaoEvent;
|
|||||||
import com.imyeyu.api.modules.gao.entity.GaoEventOption;
|
import com.imyeyu.api.modules.gao.entity.GaoEventOption;
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoEventOptionGroup;
|
import com.imyeyu.api.modules.gao.entity.GaoEventOptionGroup;
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoEventRoleRelation;
|
import com.imyeyu.api.modules.gao.entity.GaoEventRoleRelation;
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoPackageConfig;
|
||||||
import com.imyeyu.api.modules.gao.mapper.GaoEventMapper;
|
import com.imyeyu.api.modules.gao.mapper.GaoEventMapper;
|
||||||
import com.imyeyu.api.modules.gao.mapper.GaoEventOptionGroupMapper;
|
import com.imyeyu.api.modules.gao.mapper.GaoEventOptionGroupMapper;
|
||||||
import com.imyeyu.api.modules.gao.mapper.GaoEventOptionMapper;
|
import com.imyeyu.api.modules.gao.mapper.GaoEventOptionMapper;
|
||||||
import com.imyeyu.api.modules.gao.mapper.GaoEventRecordMapper;
|
import com.imyeyu.api.modules.gao.mapper.GaoEventRecordMapper;
|
||||||
import com.imyeyu.api.modules.gao.mapper.GaoEventRoleRelationMapper;
|
import com.imyeyu.api.modules.gao.mapper.GaoEventRoleRelationMapper;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoEventService;
|
import com.imyeyu.api.modules.gao.service.GaoEventService;
|
||||||
|
import com.imyeyu.api.modules.gao.service.GaoPackageConfigService;
|
||||||
import com.imyeyu.api.modules.system.entity.Logger;
|
import com.imyeyu.api.modules.system.entity.Logger;
|
||||||
import com.imyeyu.api.modules.system.service.LoggerService;
|
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
@@ -57,6 +59,7 @@ public class GaoEventServiceImplement extends AbstractEntityService<GaoEvent, St
|
|||||||
private final GaoEventOptionMapper optionMapper;
|
private final GaoEventOptionMapper optionMapper;
|
||||||
private final GaoEventRecordMapper eventRecordMapper;
|
private final GaoEventRecordMapper eventRecordMapper;
|
||||||
private final GaoEventRoleRelationMapper roleRelationMapper;
|
private final GaoEventRoleRelationMapper roleRelationMapper;
|
||||||
|
private final GaoPackageConfigService packageConfigService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BaseMapper<GaoEvent, String> mapper() {
|
protected BaseMapper<GaoEvent, String> mapper() {
|
||||||
@@ -130,6 +133,10 @@ public class GaoEventServiceImplement extends AbstractEntityService<GaoEvent, St
|
|||||||
GaoEvent.BizType bizType = TimiJava.defaultIfNull(event.getBizType(), dbEvent.getBizType());
|
GaoEvent.BizType bizType = TimiJava.defaultIfNull(event.getBizType(), dbEvent.getBizType());
|
||||||
TimiException.requiredTrue(bizType == TimiJava.defaultIfNull(dbEvent.getBizType(), GaoEvent.BizType.GENERAL), "事件业务类型创建后不可修改");
|
TimiException.requiredTrue(bizType == TimiJava.defaultIfNull(dbEvent.getBizType(), GaoEvent.BizType.GENERAL), "事件业务类型创建后不可修改");
|
||||||
dbEvent.setBizType(bizType);
|
dbEvent.setBizType(bizType);
|
||||||
|
if (event.getPackageConfigId() != null && !event.getPackageConfigId().equals(dbEvent.getPackageConfigId())) {
|
||||||
|
TimiException.requiredTrue(0 == eventRecordMapper.countByEventId(dbEvent.getId()), "已有登记记录的事件不能更换绑定套餐");
|
||||||
|
dbEvent.setPackageConfigId(event.getPackageConfigId());
|
||||||
|
}
|
||||||
dbEvent.setValueType(TimiJava.defaultIfNull(event.getValueType(), oldValueType));
|
dbEvent.setValueType(TimiJava.defaultIfNull(event.getValueType(), oldValueType));
|
||||||
if (event.getValueUnit() != null) {
|
if (event.getValueUnit() != null) {
|
||||||
dbEvent.setValueUnit(event.getValueUnit());
|
dbEvent.setValueUnit(event.getValueUnit());
|
||||||
@@ -317,6 +324,12 @@ public class GaoEventServiceImplement extends AbstractEntityService<GaoEvent, St
|
|||||||
event.setBizType(TimiJava.defaultIfNull(event.getBizType(), GaoEvent.BizType.GENERAL));
|
event.setBizType(TimiJava.defaultIfNull(event.getBizType(), GaoEvent.BizType.GENERAL));
|
||||||
if (event.getBizType() == GaoEvent.BizType.PACKAGE_PURCHASE) {
|
if (event.getBizType() == GaoEvent.BizType.PACKAGE_PURCHASE) {
|
||||||
TimiException.requiredTrue(!Boolean.TRUE.equals(event.getRequireVerification()), "购买套餐事件不能要求核销");
|
TimiException.requiredTrue(!Boolean.TRUE.equals(event.getRequireVerification()), "购买套餐事件不能要求核销");
|
||||||
|
TimiException.required(event.getPackageConfigId(), "购买套餐事件必须绑定套餐配置");
|
||||||
|
GaoPackageConfig packageConfig = packageConfigService.get(event.getPackageConfigId());
|
||||||
|
TimiException.required(packageConfig, "购买套餐事件绑定的套餐配置不存在");
|
||||||
|
TimiException.requiredTrue(event.getStoreId().equals(packageConfig.getStoreId()), "购买事件和套餐配置不属于同一门店");
|
||||||
|
} else {
|
||||||
|
TimiException.requiredNull(event.getPackageConfigId(), "普通事件不能绑定套餐配置");
|
||||||
}
|
}
|
||||||
GaoEvent.ValueType valueType = TimiJava.defaultIfNull(event.getValueType(), GaoEvent.ValueType.NONE);
|
GaoEvent.ValueType valueType = TimiJava.defaultIfNull(event.getValueType(), GaoEvent.ValueType.NONE);
|
||||||
if (valueType == GaoEvent.ValueType.NONE) {
|
if (valueType == GaoEvent.ValueType.NONE) {
|
||||||
|
|||||||
+12
@@ -7,6 +7,7 @@ import com.imyeyu.api.modules.system.entity.Logger;
|
|||||||
import com.imyeyu.api.modules.system.service.LoggerService;
|
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||||
import com.imyeyu.api.modules.gao.mapper.GaoPackageConfigItemMapper;
|
import com.imyeyu.api.modules.gao.mapper.GaoPackageConfigItemMapper;
|
||||||
import com.imyeyu.api.modules.gao.mapper.GaoPackageConfigMapper;
|
import com.imyeyu.api.modules.gao.mapper.GaoPackageConfigMapper;
|
||||||
|
import com.imyeyu.api.modules.gao.mapper.GaoEventMapper;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoPackageConfigService;
|
import com.imyeyu.api.modules.gao.service.GaoPackageConfigService;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoPackageConfigPage;
|
import com.imyeyu.api.modules.gao.vo.GaoPackageConfigPage;
|
||||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||||
@@ -37,6 +38,7 @@ public class GaoPackageConfigServiceImplement extends AbstractEntityService<GaoP
|
|||||||
|
|
||||||
private final GaoPackageConfigMapper mapper;
|
private final GaoPackageConfigMapper mapper;
|
||||||
private final GaoPackageConfigItemMapper itemMapper;
|
private final GaoPackageConfigItemMapper itemMapper;
|
||||||
|
private final GaoEventMapper eventMapper;
|
||||||
private final UserLoginService userLoginService;
|
private final UserLoginService userLoginService;
|
||||||
private final LoggerService loggerService;
|
private final LoggerService loggerService;
|
||||||
|
|
||||||
@@ -60,6 +62,15 @@ public class GaoPackageConfigServiceImplement extends AbstractEntityService<GaoP
|
|||||||
return mapper.selectValidList(storeId, Time.now());
|
return mapper.selectValidList(storeId, Time.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, GaoPackageConfig> mapByIdList(Collection<String> idList) {
|
||||||
|
if (idList == null || idList.isEmpty()) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
return mapper.selectByIdList(idList).stream()
|
||||||
|
.collect(java.util.stream.Collectors.toMap(GaoPackageConfig::getId, item -> item));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GaoPackageConfigItem> listItemByPackageConfigId(String packageConfigId) {
|
public List<GaoPackageConfigItem> listItemByPackageConfigId(String packageConfigId) {
|
||||||
TimiException.required(packageConfigId, "not found packageConfigId");
|
TimiException.required(packageConfigId, "not found packageConfigId");
|
||||||
@@ -134,6 +145,7 @@ public class GaoPackageConfigServiceImplement extends AbstractEntityService<GaoP
|
|||||||
loggerService.execute(Logger.Module.GAO, "GAO_PACKAGE_CONFIG_DELETE", id, () -> {
|
loggerService.execute(Logger.Module.GAO, "GAO_PACKAGE_CONFIG_DELETE", id, () -> {
|
||||||
GaoPackageConfig config = get(id);
|
GaoPackageConfig config = get(id);
|
||||||
TimiException.required(config, "not found package config");
|
TimiException.required(config, "not found package config");
|
||||||
|
TimiException.requiredTrue(0 == eventMapper.countByPackageConfigId(id), "套餐配置已绑定购买事件,不能删除");
|
||||||
super.delete(id);
|
super.delete(id);
|
||||||
return id;
|
return id;
|
||||||
});
|
});
|
||||||
|
|||||||
+1
-1
@@ -182,7 +182,7 @@ public class GaoPackageDeliveryServiceImplement extends AbstractEntityService<Ga
|
|||||||
BigDecimal reservedBefore = decimal(packageItem.getReservedQuantity());
|
BigDecimal reservedBefore = decimal(packageItem.getReservedQuantity());
|
||||||
BigDecimal deliveredBefore = decimal(packageItem.getDeliveredQuantity());
|
BigDecimal deliveredBefore = decimal(packageItem.getDeliveredQuantity());
|
||||||
BigDecimal available = decimal(packageItem.getTotalQuantity()).subtract(reservedBefore).subtract(deliveredBefore);
|
BigDecimal available = decimal(packageItem.getTotalQuantity()).subtract(reservedBefore).subtract(deliveredBefore);
|
||||||
TimiException.requiredTrue(0 < requestItem.getQuantity().compareTo(available), "产品可发数量不足");
|
TimiException.requiredTrue(0 <= available.compareTo(requestItem.getQuantity()), "产品可发数量不足");
|
||||||
int updated = customerPackageService.updateItemReservedQuantity(packageItem.getId(), requestItem.getQuantity());
|
int updated = customerPackageService.updateItemReservedQuantity(packageItem.getId(), requestItem.getQuantity());
|
||||||
TimiException.requiredTrue(0 < updated, "产品可发数量不足");
|
TimiException.requiredTrue(0 < updated, "产品可发数量不足");
|
||||||
GaoPackageDeliveryItem savedItem = copyDeliveryItem(requestItem);
|
GaoPackageDeliveryItem savedItem = copyDeliveryItem(requestItem);
|
||||||
|
|||||||
@@ -21,16 +21,13 @@ public class GaoCustomerPackagePurchaseRequest {
|
|||||||
/// 客户 ID
|
/// 客户 ID
|
||||||
private String customerId;
|
private String customerId;
|
||||||
|
|
||||||
/// 套餐配置 ID
|
/// 实际成交价,单位分,空为事件绑定套餐的标准价
|
||||||
private String packageConfigId;
|
|
||||||
|
|
||||||
/// 实际成交价,单位分
|
|
||||||
private Long saleAmount;
|
private Long saleAmount;
|
||||||
|
|
||||||
/// 购买时间
|
/// 购买时间
|
||||||
private Long purchasedAt;
|
private Long purchasedAt;
|
||||||
|
|
||||||
/// 最终产品明细
|
/// 最终产品明细,空为事件绑定套餐的默认产品明细
|
||||||
private List<GaoCustomerPackagePurchaseItem> itemList;
|
private List<GaoCustomerPackagePurchaseItem> itemList;
|
||||||
|
|
||||||
/// 购买照片
|
/// 购买照片
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ public class InitBuiltinUser implements ApplicationRunner {
|
|||||||
private void bindBuiltinRoleParent(Map<String, Role> roleMap) {
|
private void bindBuiltinRoleParent(Map<String, Role> roleMap) {
|
||||||
setRoleParent(roleMap, ModuleCode.CORE, CoreRoleCode.ADMIN.name(), ModuleCode.CORE, CoreRoleCode.SYSTEM.name());
|
setRoleParent(roleMap, ModuleCode.CORE, CoreRoleCode.ADMIN.name(), ModuleCode.CORE, CoreRoleCode.SYSTEM.name());
|
||||||
setRoleParent(roleMap, ModuleCode.GAO, GaoRoleCode.GLOBAL_MANAGER.name(), ModuleCode.CORE, CoreRoleCode.ADMIN.name());
|
setRoleParent(roleMap, ModuleCode.GAO, GaoRoleCode.GLOBAL_MANAGER.name(), ModuleCode.CORE, CoreRoleCode.ADMIN.name());
|
||||||
|
setRoleParent(roleMap, ModuleCode.GAO, GaoRoleCode.STORE_MANAGER.name(), ModuleCode.GAO, GaoRoleCode.GLOBAL_MANAGER.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 按权限定义补齐 SYSTEM 和 ADMIN 的默认权限
|
/// 按权限定义补齐 SYSTEM 和 ADMIN 的默认权限
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package db.migration.timiserver;
|
||||||
|
|
||||||
|
import org.flywaydb.core.api.migration.BaseJavaMigration;
|
||||||
|
import org.flywaydb.core.api.migration.Context;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
|
||||||
|
/// 对账附件名称字段长度
|
||||||
|
///
|
||||||
|
/// 生产环境可能已经紧急扩容,达到目标长度时不重复执行 DDL
|
||||||
|
public class V50__reconcile_attachment_name_length extends BaseJavaMigration {
|
||||||
|
|
||||||
|
private static final int NAME_LENGTH = 255;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void migrate(Context context) throws Exception {
|
||||||
|
Connection connection = context.getConnection();
|
||||||
|
int attachmentNameLength = queryCurrentLength(connection, "attachment");
|
||||||
|
int variantNameLength = queryCurrentLength(connection, "attachment_variant");
|
||||||
|
reconcile(connection, "attachment", attachmentNameLength);
|
||||||
|
reconcile(connection, "attachment_variant", variantNameLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 将名称字段扩容到目标长度
|
||||||
|
///
|
||||||
|
/// @param connection Flyway 数据库连接
|
||||||
|
/// @param tableName 表名
|
||||||
|
/// @param currentLength 当前字符长度
|
||||||
|
/// @throws SQLException DDL 执行失败
|
||||||
|
private void reconcile(Connection connection, String tableName, int currentLength) throws SQLException {
|
||||||
|
if (NAME_LENGTH <= currentLength) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sql = """
|
||||||
|
ALTER TABLE `%s`
|
||||||
|
MODIFY COLUMN `name` VARCHAR(%d) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL
|
||||||
|
""".formatted(tableName, NAME_LENGTH);
|
||||||
|
try (Statement statement = connection.createStatement()) {
|
||||||
|
statement.executeUpdate(sql);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 查询名称字段当前长度
|
||||||
|
///
|
||||||
|
/// @param connection Flyway 数据库连接
|
||||||
|
/// @param tableName 表名
|
||||||
|
/// @return 当前字符长度
|
||||||
|
/// @throws SQLException 表或字段不存在、字段类型不正确或查询失败
|
||||||
|
private int queryCurrentLength(Connection connection, String tableName) throws SQLException {
|
||||||
|
String sql = """
|
||||||
|
SELECT `DATA_TYPE`, `CHARACTER_MAXIMUM_LENGTH`
|
||||||
|
FROM `INFORMATION_SCHEMA`.`COLUMNS`
|
||||||
|
WHERE `TABLE_SCHEMA` = DATABASE()
|
||||||
|
AND `TABLE_NAME` = ?
|
||||||
|
AND `COLUMN_NAME` = 'name'
|
||||||
|
""";
|
||||||
|
try (PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||||
|
statement.setString(1, tableName);
|
||||||
|
try (ResultSet resultSet = statement.executeQuery()) {
|
||||||
|
if (!resultSet.next()) {
|
||||||
|
throw new SQLException("表 %s 的 name 字段不存在".formatted(tableName));
|
||||||
|
}
|
||||||
|
String dataType = resultSet.getString("DATA_TYPE");
|
||||||
|
if (!"varchar".equalsIgnoreCase(dataType)) {
|
||||||
|
throw new SQLException("表 %s 的 name 字段类型不是 VARCHAR,而是 %s".formatted(tableName, dataType));
|
||||||
|
}
|
||||||
|
return resultSet.getInt("CHARACTER_MAXIMUM_LENGTH");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
ALTER TABLE `gao_event_record`
|
||||||
|
ADD COLUMN `updated_by` VARCHAR(36) NULL COMMENT '最后修改用户 ID' AFTER `updated_at`;
|
||||||
|
|
||||||
|
UPDATE `gao_event_record`
|
||||||
|
SET `updated_by` = `operator_user_id`
|
||||||
|
WHERE `updated_by` IS NULL;
|
||||||
|
|
||||||
|
ALTER TABLE `gao_event_record`
|
||||||
|
MODIFY COLUMN `updated_by` VARCHAR(36) NOT NULL COMMENT '最后修改用户 ID';
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE `gao_event`
|
||||||
|
ADD COLUMN `package_config_id` VARCHAR(36) NULL COMMENT '购买套餐事件绑定的套餐配置 ID' AFTER `biz_type`,
|
||||||
|
ADD KEY `idx_gao_event_package_config` (`package_config_id`, `deleted_at`);
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
UPDATE `role_permission_inherit` inherit
|
||||||
|
JOIN `role` parent_role ON parent_role.id = inherit.parent_role_id
|
||||||
|
JOIN `role` child_role ON child_role.id = inherit.child_role_id
|
||||||
|
SET inherit.deleted_at = UNIX_TIMESTAMP() * 1000
|
||||||
|
WHERE
|
||||||
|
inherit.deleted_at IS NULL
|
||||||
|
AND parent_role.module_code = 'GAO'
|
||||||
|
AND parent_role.code = 'GLOBAL_MANAGER'
|
||||||
|
AND child_role.module_code = 'GAO'
|
||||||
|
AND child_role.code = 'STORE_MANAGER';
|
||||||
@@ -25,11 +25,15 @@
|
|||||||
<update id="updateReservedQuantity">
|
<update id="updateReservedQuantity">
|
||||||
UPDATE `gao_customer_package_item`
|
UPDATE `gao_customer_package_item`
|
||||||
SET `reserved_quantity` = `reserved_quantity` + #{delta}, `updated_at` = FLOOR(UNIX_TIMESTAMP(NOW(3)) * 1000)
|
SET `reserved_quantity` = `reserved_quantity` + #{delta}, `updated_at` = FLOOR(UNIX_TIMESTAMP(NOW(3)) * 1000)
|
||||||
WHERE `id` = #{id} AND `deleted_at` IS NULL AND `reserved_quantity` + #{delta} >= 0
|
WHERE `id` = #{id} AND `deleted_at` IS NULL
|
||||||
|
AND `reserved_quantity` + #{delta} >= 0
|
||||||
|
AND `reserved_quantity` + `delivered_quantity` + #{delta} <= `total_quantity`
|
||||||
</update>
|
</update>
|
||||||
<update id="updateDeliveredQuantity">
|
<update id="updateDeliveredQuantity">
|
||||||
UPDATE `gao_customer_package_item`
|
UPDATE `gao_customer_package_item`
|
||||||
SET `delivered_quantity` = `delivered_quantity` + #{delta}, `updated_at` = FLOOR(UNIX_TIMESTAMP(NOW(3)) * 1000)
|
SET `delivered_quantity` = `delivered_quantity` + #{delta}, `updated_at` = FLOOR(UNIX_TIMESTAMP(NOW(3)) * 1000)
|
||||||
WHERE `id` = #{id} AND `deleted_at` IS NULL AND `delivered_quantity` + #{delta} >= 0
|
WHERE `id` = #{id} AND `deleted_at` IS NULL
|
||||||
|
AND `delivered_quantity` + #{delta} >= 0
|
||||||
|
AND `reserved_quantity` + `delivered_quantity` + #{delta} <= `total_quantity`
|
||||||
</update>
|
</update>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -65,6 +65,7 @@
|
|||||||
`verification_status` = 'VERIFIED',
|
`verification_status` = 'VERIFIED',
|
||||||
`verifier_user_id` = #{verifierUserId},
|
`verifier_user_id` = #{verifierUserId},
|
||||||
`verified_at` = #{verifiedAt},
|
`verified_at` = #{verifiedAt},
|
||||||
|
`updated_by` = #{updatedBy},
|
||||||
`updated_at` = ROUND(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000)
|
`updated_at` = ROUND(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000)
|
||||||
WHERE
|
WHERE
|
||||||
`id` = #{id}
|
`id` = #{id}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
SELECT DISTINCT
|
SELECT DISTINCT
|
||||||
permission.*
|
permission.*
|
||||||
FROM `role_permission`
|
FROM `role_permission`
|
||||||
LEFT JOIN `permission` ON permission.id = role_permission.permission_id
|
INNER JOIN `permission` ON permission.id = role_permission.permission_id
|
||||||
WHERE
|
WHERE
|
||||||
`role_permission`.`role_id` IN
|
`role_permission`.`role_id` IN
|
||||||
<foreach collection="roleIdList" item="item" separator="," open="(" close=")">
|
<foreach collection="roleIdList" item="item" separator="," open="(" close=")">
|
||||||
|
|||||||
Reference in New Issue
Block a user