|
@@ -0,0 +1,452 @@
|
|
|
|
|
+package shop.alien.store.service.impl;
|
|
|
|
|
+
|
|
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
+import shop.alien.entity.store.StoreReceiptTemplateConfig;
|
|
|
|
|
+import shop.alien.entity.store.dto.StoreReceiptTemplateCreateDTO;
|
|
|
|
|
+import shop.alien.entity.store.dto.StoreReceiptTemplateEditDTO;
|
|
|
|
|
+import shop.alien.entity.store.dto.StoreReceiptTemplateDeleteDTO;
|
|
|
|
|
+import shop.alien.entity.store.dto.StoreReceiptTemplateSaveDTO;
|
|
|
|
|
+import shop.alien.mapper.StoreReceiptTemplateConfigMapper;
|
|
|
|
|
+import shop.alien.store.service.StoreReceiptTemplateConfigService;
|
|
|
|
|
+import shop.alien.util.common.JwtUtil;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.Arrays;
|
|
|
|
|
+import java.util.Date;
|
|
|
|
|
+import java.util.HashSet;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.Set;
|
|
|
|
|
+
|
|
|
|
|
+@Slf4j
|
|
|
|
|
+@Service
|
|
|
|
|
+@RequiredArgsConstructor
|
|
|
|
|
+public class StoreReceiptTemplateConfigServiceImpl implements StoreReceiptTemplateConfigService {
|
|
|
|
|
+
|
|
|
|
|
+ private final StoreReceiptTemplateConfigMapper storeReceiptTemplateConfigMapper;
|
|
|
|
|
+
|
|
|
|
|
+ private static final Set<String> SUPPORTED_FIELD_KEYS = new HashSet<>(Arrays.asList(
|
|
|
|
|
+ "ticketName", "storeName", "orderNo", "tableNo", "peopleCount", "diningTime", "cashierTime", "name", "phone",
|
|
|
|
|
+ "customData", "beginRemark",
|
|
|
|
|
+ "item", "wholeRemark", "countSubtotal", "orderPrice",
|
|
|
|
|
+ "paymentDiscount", "paymentInfo",
|
|
|
|
|
+ "orderBy", "orderAt", "printBy", "printAt", "customImage", "customText", "storeAddress", "storeTel"
|
|
|
|
|
+ ));
|
|
|
|
|
+
|
|
|
|
|
+ private static final Set<String> SUPPORTED_SUB_KEYS = new HashSet<>(Arrays.asList(
|
|
|
|
|
+ "unitPrice", "quantity", "subtotal",
|
|
|
|
|
+ "dishPriceTotal", "serviceFeeTotal", "otherServiceFeeTotal", "chargeReason", "orderTotal",
|
|
|
|
|
+ "coupon", "manualReduction", "reductionReason",
|
|
|
|
|
+ "settlementMethod", "paymentMethod", "paymentTotal", "divider"
|
|
|
|
|
+ ));
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public List<StoreReceiptTemplateConfig> listByStoreAndReceiptType(Integer storeId, Integer receiptType) {
|
|
|
|
|
+ validateStoreAndReceiptType(storeId, receiptType);
|
|
|
|
|
+ ensureDefaultTemplate(storeId, receiptType);
|
|
|
|
|
+ LambdaQueryWrapper<StoreReceiptTemplateConfig> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ wrapper.eq(StoreReceiptTemplateConfig::getStoreId, storeId)
|
|
|
|
|
+ .eq(StoreReceiptTemplateConfig::getReceiptType, receiptType)
|
|
|
|
|
+ .eq(StoreReceiptTemplateConfig::getDeleteFlag, 0)
|
|
|
|
|
+ .orderByAsc(StoreReceiptTemplateConfig::getTemplateType, StoreReceiptTemplateConfig::getId);
|
|
|
|
|
+ return storeReceiptTemplateConfigMapper.selectList(wrapper);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public Boolean deleteTemplateById(StoreReceiptTemplateDeleteDTO dto) {
|
|
|
|
|
+ if (dto == null || dto.getId() == null || dto.getId() <= 0) {
|
|
|
|
|
+ throw new RuntimeException("模板ID不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ StoreReceiptTemplateConfig existing = storeReceiptTemplateConfigMapper.selectById(dto.getId());
|
|
|
|
|
+ if (existing == null || (existing.getDeleteFlag() != null && existing.getDeleteFlag() == 1)) {
|
|
|
|
|
+ return true; // 视为已删除
|
|
|
|
|
+ }
|
|
|
|
|
+ if (dto.getStoreId() != null && !dto.getStoreId().equals(existing.getStoreId())) {
|
|
|
|
|
+ throw new RuntimeException("模板归属不匹配,禁止删除");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (existing.getTemplateType() != null && existing.getTemplateType() == 1) {
|
|
|
|
|
+ throw new RuntimeException("默认模板不可删除");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ LambdaUpdateWrapper<StoreReceiptTemplateConfig> wrapper = new LambdaUpdateWrapper<>();
|
|
|
|
|
+ wrapper.eq(StoreReceiptTemplateConfig::getId, dto.getId());
|
|
|
|
|
+ wrapper.set(StoreReceiptTemplateConfig::getDeleteFlag, 1);
|
|
|
|
|
+ wrapper.set(StoreReceiptTemplateConfig::getUpdatedTime, new Date());
|
|
|
|
|
+ return storeReceiptTemplateConfigMapper.update(null, wrapper) > 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public StoreReceiptTemplateConfig getDetail(Integer storeId, Integer receiptType, Integer templateType) {
|
|
|
|
|
+ validateStoreAndReceiptType(storeId, receiptType);
|
|
|
|
|
+ validateTemplateType(templateType);
|
|
|
|
|
+ ensureDefaultTemplate(storeId, receiptType);
|
|
|
|
|
+ return getOne(storeId, receiptType, templateType);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+// @Override
|
|
|
|
|
+// @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+// public StoreReceiptTemplateConfig createTemplate(StoreReceiptTemplateCreateDTO dto) {
|
|
|
|
|
+// if (dto == null) {
|
|
|
|
|
+// throw new RuntimeException("参数不能为空");
|
|
|
|
|
+// }
|
|
|
|
|
+// validateStoreAndReceiptType(dto.getStoreId(), dto.getReceiptType());
|
|
|
|
|
+// if (StringUtils.isBlank(dto.getTemplateName())) {
|
|
|
|
|
+// throw new RuntimeException("模板名称不能为空");
|
|
|
|
|
+// }
|
|
|
|
|
+// ensureDefaultTemplate(dto.getStoreId(), dto.getReceiptType());
|
|
|
|
|
+//
|
|
|
|
|
+// // 创建与编辑保存走同一套保存逻辑;新建时用默认模板配置初始化自定义模板
|
|
|
|
|
+// StoreReceiptTemplateConfig defaultTemplate = getOne(dto.getStoreId(), dto.getReceiptType(), 1);
|
|
|
|
|
+// String initConfig = defaultTemplate != null ? defaultTemplate.getTemplateConfigJson() : buildDefaultTemplateJson();
|
|
|
|
|
+//
|
|
|
|
|
+// StoreReceiptTemplateSaveDTO saveDTO = new StoreReceiptTemplateSaveDTO();
|
|
|
|
|
+// saveDTO.setStoreId(dto.getStoreId());
|
|
|
|
|
+// saveDTO.setReceiptType(dto.getReceiptType());
|
|
|
|
|
+// saveDTO.setTemplateType(2);
|
|
|
|
|
+// saveDTO.setTemplateName(dto.getTemplateName().trim());
|
|
|
|
|
+// saveDTO.setEnabled(0);
|
|
|
|
|
+// saveDTO.setTemplateConfigJson(initConfig);
|
|
|
|
|
+// return saveTemplate(saveDTO);
|
|
|
|
|
+// }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public StoreReceiptTemplateConfig saveTemplate(StoreReceiptTemplateSaveDTO dto) {
|
|
|
|
|
+ validateSaveDto(dto);
|
|
|
|
|
+ validateTemplateConfigJson(dto.getTemplateConfigJson());
|
|
|
|
|
+ ensureDefaultTemplate(dto.getStoreId(), dto.getReceiptType());
|
|
|
|
|
+
|
|
|
|
|
+ StoreReceiptTemplateConfig existing = getOne(dto.getStoreId(), dto.getReceiptType(), dto.getTemplateType());
|
|
|
|
|
+ Integer userId = getCurrentUserId();
|
|
|
|
|
+ if (existing == null) {
|
|
|
|
|
+ existing = new StoreReceiptTemplateConfig();
|
|
|
|
|
+ existing.setStoreId(dto.getStoreId());
|
|
|
|
|
+ existing.setReceiptType(dto.getReceiptType());
|
|
|
|
|
+ existing.setTemplateType(dto.getTemplateType());
|
|
|
|
|
+ existing.setTemplateName(defaultTemplateName(dto.getTemplateType()));
|
|
|
|
|
+ existing.setEnabled(dto.getTemplateType() == 1 ? 1 : 0);
|
|
|
|
|
+ existing.setTemplateConfigJson(buildDefaultTemplateJson());
|
|
|
|
|
+ existing.setDeleteFlag(0);
|
|
|
|
|
+ existing.setCreatedTime(new Date());
|
|
|
|
|
+ existing.setCreatedUserId(userId);
|
|
|
|
|
+ storeReceiptTemplateConfigMapper.insert(existing);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (StringUtils.isNotBlank(dto.getTemplateName())) {
|
|
|
|
|
+ existing.setTemplateName(dto.getTemplateName().trim());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (dto.getEnabled() != null) {
|
|
|
|
|
+ existing.setEnabled(dto.getEnabled() == 1 ? 1 : 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ existing.setTemplateConfigJson(dto.getTemplateConfigJson());
|
|
|
|
|
+ existing.setUpdatedTime(new Date());
|
|
|
|
|
+ existing.setUpdatedUserId(userId);
|
|
|
|
|
+ storeReceiptTemplateConfigMapper.updateById(existing);
|
|
|
|
|
+
|
|
|
|
|
+ if (existing.getEnabled() != null && existing.getEnabled() == 1) {
|
|
|
|
|
+ // 一个类型只允许一个启用模板
|
|
|
|
|
+ LambdaUpdateWrapper<StoreReceiptTemplateConfig> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
|
|
+ updateWrapper.eq(StoreReceiptTemplateConfig::getStoreId, existing.getStoreId())
|
|
|
|
|
+ .eq(StoreReceiptTemplateConfig::getReceiptType, existing.getReceiptType())
|
|
|
|
|
+ .ne(StoreReceiptTemplateConfig::getId, existing.getId())
|
|
|
|
|
+ .set(StoreReceiptTemplateConfig::getEnabled, 0);
|
|
|
|
|
+ storeReceiptTemplateConfigMapper.update(null, updateWrapper);
|
|
|
|
|
+ }
|
|
|
|
|
+ return getOne(existing.getStoreId(), existing.getReceiptType(), existing.getTemplateType());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public StoreReceiptTemplateConfig resetToDefault(Integer storeId, Integer receiptType, Integer templateType) {
|
|
|
|
|
+ validateStoreAndReceiptType(storeId, receiptType);
|
|
|
|
|
+ validateTemplateType(templateType);
|
|
|
|
|
+ ensureDefaultTemplate(storeId, receiptType);
|
|
|
|
|
+ StoreReceiptTemplateConfig existing = getOne(storeId, receiptType, templateType);
|
|
|
|
|
+ if (existing == null) {
|
|
|
|
|
+ throw new RuntimeException("模板不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+ existing.setTemplateConfigJson(buildDefaultTemplateJson());
|
|
|
|
|
+ existing.setUpdatedTime(new Date());
|
|
|
|
|
+ existing.setUpdatedUserId(getCurrentUserId());
|
|
|
|
|
+ storeReceiptTemplateConfigMapper.updateById(existing);
|
|
|
|
|
+ return existing;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void ensureDefaultTemplate(Integer storeId, Integer receiptType) {
|
|
|
|
|
+ StoreReceiptTemplateConfig defaultTemplate = getOne(storeId, receiptType, 1);
|
|
|
|
|
+ if (defaultTemplate == null) {
|
|
|
|
|
+ createDefault(storeId, receiptType, 1, "默认模板", 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void createDefault(Integer storeId, Integer receiptType, Integer templateType, String templateName, Integer enabled) {
|
|
|
|
|
+ StoreReceiptTemplateConfig config = new StoreReceiptTemplateConfig();
|
|
|
|
|
+ config.setStoreId(storeId);
|
|
|
|
|
+ config.setReceiptType(receiptType);
|
|
|
|
|
+ config.setTemplateType(templateType);
|
|
|
|
|
+ config.setTemplateName(templateName);
|
|
|
|
|
+ config.setEnabled(enabled);
|
|
|
|
|
+ config.setTemplateConfigJson(buildDefaultTemplateJson());
|
|
|
|
|
+ config.setDeleteFlag(0);
|
|
|
|
|
+ config.setCreatedTime(new Date());
|
|
|
|
|
+ config.setCreatedUserId(getCurrentUserId());
|
|
|
|
|
+ storeReceiptTemplateConfigMapper.insert(config);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private StoreReceiptTemplateConfig getOne(Integer storeId, Integer receiptType, Integer templateType) {
|
|
|
|
|
+ LambdaQueryWrapper<StoreReceiptTemplateConfig> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ wrapper.eq(StoreReceiptTemplateConfig::getStoreId, storeId)
|
|
|
|
|
+ .eq(StoreReceiptTemplateConfig::getReceiptType, receiptType)
|
|
|
|
|
+ .eq(StoreReceiptTemplateConfig::getTemplateType, templateType)
|
|
|
|
|
+ .eq(StoreReceiptTemplateConfig::getDeleteFlag, 0)
|
|
|
|
|
+ .last("limit 1");
|
|
|
|
|
+ return storeReceiptTemplateConfigMapper.selectOne(wrapper);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void validateSaveDto(StoreReceiptTemplateSaveDTO dto) {
|
|
|
|
|
+ if (dto == null) {
|
|
|
|
|
+ throw new RuntimeException("参数不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ validateStoreAndReceiptType(dto.getStoreId(), dto.getReceiptType());
|
|
|
|
|
+ validateTemplateType(dto.getTemplateType());
|
|
|
|
|
+ if (StringUtils.isBlank(dto.getTemplateConfigJson())) {
|
|
|
|
|
+ throw new RuntimeException("模板配置不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Override
|
|
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
|
|
+ public StoreReceiptTemplateConfig updateTemplateById(StoreReceiptTemplateEditDTO dto) {
|
|
|
|
|
+ if (dto == null || dto.getId() == null || dto.getId() <= 0) {
|
|
|
|
|
+ throw new RuntimeException("模板ID不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ validateStoreAndReceiptType(dto.getStoreId(), dto.getReceiptType());
|
|
|
|
|
+ validateTemplateType(dto.getTemplateType());
|
|
|
|
|
+ validateTemplateConfigJson(dto.getTemplateConfigJson());
|
|
|
|
|
+
|
|
|
|
|
+ StoreReceiptTemplateConfig existing = storeReceiptTemplateConfigMapper.selectById(dto.getId());
|
|
|
|
|
+ if (existing == null || existing.getDeleteFlag() != null && existing.getDeleteFlag() == 1) {
|
|
|
|
|
+ throw new RuntimeException("模板不存在或已删除");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!existing.getStoreId().equals(dto.getStoreId())
|
|
|
|
|
+ || !existing.getReceiptType().equals(dto.getReceiptType())
|
|
|
|
|
+ || !existing.getTemplateType().equals(dto.getTemplateType())) {
|
|
|
|
|
+ throw new RuntimeException("模板归属不匹配,禁止跨店铺或跨类型修改");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (StringUtils.isNotBlank(dto.getTemplateName())) {
|
|
|
|
|
+ existing.setTemplateName(dto.getTemplateName().trim());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (dto.getEnabled() != null) {
|
|
|
|
|
+ existing.setEnabled(dto.getEnabled() == 1 ? 1 : 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ existing.setTemplateConfigJson(dto.getTemplateConfigJson());
|
|
|
|
|
+ existing.setUpdatedTime(new Date());
|
|
|
|
|
+ existing.setUpdatedUserId(getCurrentUserId());
|
|
|
|
|
+ storeReceiptTemplateConfigMapper.updateById(existing);
|
|
|
|
|
+
|
|
|
|
|
+ if (existing.getEnabled() != null && existing.getEnabled() == 1) {
|
|
|
|
|
+ LambdaUpdateWrapper<StoreReceiptTemplateConfig> updateWrapper = new LambdaUpdateWrapper<>();
|
|
|
|
|
+ updateWrapper.eq(StoreReceiptTemplateConfig::getStoreId, existing.getStoreId())
|
|
|
|
|
+ .eq(StoreReceiptTemplateConfig::getReceiptType, existing.getReceiptType())
|
|
|
|
|
+ .ne(StoreReceiptTemplateConfig::getId, existing.getId())
|
|
|
|
|
+ .set(StoreReceiptTemplateConfig::getEnabled, 0);
|
|
|
|
|
+ storeReceiptTemplateConfigMapper.update(null, updateWrapper);
|
|
|
|
|
+ }
|
|
|
|
|
+ return existing;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void validateStoreAndReceiptType(Integer storeId, Integer receiptType) {
|
|
|
|
|
+ if (storeId == null || storeId <= 0) {
|
|
|
|
|
+ throw new RuntimeException("门店ID不能为空且必须大于0");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (receiptType == null || (receiptType != 1 && receiptType != 2)) {
|
|
|
|
|
+ throw new RuntimeException("票据类型仅支持 1-客单, 2-结账单");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void validateTemplateType(Integer templateType) {
|
|
|
|
|
+ if (templateType == null || (templateType != 1 && templateType != 2)) {
|
|
|
|
|
+ throw new RuntimeException("模板类型仅支持 1-默认模板, 2-自定义模板");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String defaultTemplateName(Integer templateType) {
|
|
|
|
|
+ return templateType != null && templateType == 2 ? "自定义模板" : "默认模板";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private void validateTemplateConfigJson(String json) {
|
|
|
|
|
+ JSONObject root;
|
|
|
|
|
+ try {
|
|
|
|
|
+ root = JSON.parseObject(json);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ throw new RuntimeException("模板配置JSON格式不正确");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (root == null) {
|
|
|
|
|
+ throw new RuntimeException("模板配置不能为空");
|
|
|
|
|
+ }
|
|
|
|
|
+ JSONArray sections = root.getJSONArray("sections");
|
|
|
|
|
+ if (sections == null) {
|
|
|
|
|
+ throw new RuntimeException("模板配置缺少sections");
|
|
|
|
|
+ }
|
|
|
|
|
+ for (int i = 0; i < sections.size(); i++) {
|
|
|
|
|
+ JSONObject section = sections.getJSONObject(i);
|
|
|
|
|
+ if (section == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ JSONArray fields = section.getJSONArray("fields");
|
|
|
|
|
+ if (fields == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ for (int j = 0; j < fields.size(); j++) {
|
|
|
|
|
+ JSONObject field = fields.getJSONObject(j);
|
|
|
|
|
+ if (field == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ String key = field.getString("key");
|
|
|
|
|
+ if (StringUtils.isBlank(key) || !SUPPORTED_FIELD_KEYS.contains(key)) {
|
|
|
|
|
+ throw new RuntimeException("包含不支持的字段: " + key);
|
|
|
|
|
+ }
|
|
|
|
|
+ JSONArray children = field.getJSONArray("children");
|
|
|
|
|
+ if (children == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ for (int k = 0; k < children.size(); k++) {
|
|
|
|
|
+ JSONObject child = children.getJSONObject(k);
|
|
|
|
|
+ if (child == null) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ String subKey = child.getString("key");
|
|
|
|
|
+ if (StringUtils.isBlank(subKey) || !SUPPORTED_SUB_KEYS.contains(subKey)) {
|
|
|
|
|
+ throw new RuntimeException("包含不支持的子字段: " + subKey);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private Integer getCurrentUserId() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ JSONObject userInfo = JwtUtil.getCurrentUserInfo();
|
|
|
|
|
+ if (userInfo != null) {
|
|
|
|
|
+ return userInfo.getInteger("userId");
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("获取当前登录用户ID失败: {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private String buildDefaultTemplateJson() {
|
|
|
|
|
+ JSONObject root = new JSONObject();
|
|
|
|
|
+ JSONArray sections = new JSONArray();
|
|
|
|
|
+ root.put("sections", sections);
|
|
|
|
|
+
|
|
|
|
|
+ sections.add(createSection("basic", "基础信息", createBasicFields()));
|
|
|
|
|
+ sections.add(createSection("itemInfo", "品相信息", createItemFields()));
|
|
|
|
|
+ sections.add(createSection("settlement", "结算信息", createSettlementFields()));
|
|
|
|
|
+ sections.add(createSection("footer", "底栏", createFooterFields()));
|
|
|
|
|
+ return root.toJSONString();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private JSONObject createSection(String key, String name, JSONArray fields) {
|
|
|
|
|
+ JSONObject section = new JSONObject();
|
|
|
|
|
+ section.put("key", key);
|
|
|
|
|
+ section.put("name", name);
|
|
|
|
|
+ section.put("fields", fields);
|
|
|
|
|
+ return section;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private JSONArray createBasicFields() {
|
|
|
|
|
+ JSONArray fields = new JSONArray();
|
|
|
|
|
+ fields.add(createTextField("ticketName", "票据名称", true));
|
|
|
|
|
+ fields.add(createTextField("storeName", "店铺名称", true));
|
|
|
|
|
+ fields.add(createTextField("orderNo", "单号", true));
|
|
|
|
|
+ fields.add(createTextField("tableNo", "桌号", true));
|
|
|
|
|
+ fields.add(createTextField("peopleCount", "人数", true));
|
|
|
|
|
+ fields.add(createTextField("diningTime", "就餐时间", true));
|
|
|
|
|
+ fields.add(createTextField("cashierTime", "结账时间", true));
|
|
|
|
|
+ fields.add(createTextField("name", "姓名", true));
|
|
|
|
|
+ fields.add(createTextField("phone", "电话", true));
|
|
|
|
|
+ fields.add(createTextField("customData", "自定义数据", false));
|
|
|
|
|
+ fields.add(createTextField("beginRemark", "开台备注", false));
|
|
|
|
|
+ return fields;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private JSONArray createItemFields() {
|
|
|
|
|
+ JSONArray fields = new JSONArray();
|
|
|
|
|
+ fields.add(createSwitchField("item", "品项", true,
|
|
|
|
|
+ new String[]{"unitPrice", "quantity", "subtotal"},
|
|
|
|
|
+ new String[]{"单价", "数量", "小计"},
|
|
|
|
|
+ new boolean[]{true, true, true}));
|
|
|
|
|
+ fields.add(createTextField("wholeRemark", "整单备注", false));
|
|
|
|
|
+ fields.add(createTextField("countSubtotal", "数量合计", false));
|
|
|
|
|
+ fields.add(createSwitchField("orderPrice", "订单价格", true,
|
|
|
|
|
+ new String[]{"dishPriceTotal", "serviceFeeTotal", "otherServiceFeeTotal", "chargeReason", "orderTotal"},
|
|
|
|
|
+ new String[]{"菜品价格合计", "服务费合计", "其他费用合计", "收费原因", "订单合计"},
|
|
|
|
|
+ new boolean[]{true, true, false, false, true}));
|
|
|
|
|
+ return fields;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private JSONArray createSettlementFields() {
|
|
|
|
|
+ JSONArray fields = new JSONArray();
|
|
|
|
|
+ fields.add(createSwitchField("paymentDiscount", "支付优惠", true,
|
|
|
|
|
+ new String[]{"coupon", "manualReduction", "reductionReason"},
|
|
|
|
|
+ new String[]{"优惠券", "手动减免", "减免原因"},
|
|
|
|
|
+ new boolean[]{true, false, false}));
|
|
|
|
|
+ fields.add(createSwitchField("paymentInfo", "支付信息", true,
|
|
|
|
|
+ new String[]{"settlementMethod", "paymentMethod", "paymentTotal", "divider"},
|
|
|
|
|
+ new String[]{"结算方式", "支付方式", "支付合计", "分割线"},
|
|
|
|
|
+ new boolean[]{true, true, true, true}));
|
|
|
|
|
+ return fields;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private JSONArray createFooterFields() {
|
|
|
|
|
+ JSONArray fields = new JSONArray();
|
|
|
|
|
+ fields.add(createTextField("orderBy", "下单人", true));
|
|
|
|
|
+ fields.add(createTextField("orderAt", "下单时间", true));
|
|
|
|
|
+ fields.add(createTextField("printBy", "打印人", true));
|
|
|
|
|
+ fields.add(createTextField("printAt", "打印时间", true));
|
|
|
|
|
+ fields.add(createTextField("customImage", "自定义图片", false));
|
|
|
|
|
+ fields.add(createTextField("customText", "自定义文字", false));
|
|
|
|
|
+ fields.add(createTextField("storeAddress", "门店地址", false));
|
|
|
|
|
+ fields.add(createTextField("storeTel", "门店电话", false));
|
|
|
|
|
+ return fields;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private JSONObject createTextField(String key, String titleName, boolean visible) {
|
|
|
|
|
+ JSONObject field = new JSONObject();
|
|
|
|
|
+ field.put("key", key);
|
|
|
|
|
+ field.put("titleName", titleName);
|
|
|
|
|
+ field.put("visible", visible);
|
|
|
|
|
+ field.put("fontSize", "normal");
|
|
|
|
|
+ field.put("align", "left");
|
|
|
|
|
+ field.put("bold", false);
|
|
|
|
|
+ field.put("divider", false);
|
|
|
|
|
+ field.put("blankLines", 0);
|
|
|
|
|
+ return field;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private JSONObject createSwitchField(String key, String titleName, boolean visible, String[] subKeys, String[] subTitles, boolean[] subVisible) {
|
|
|
|
|
+ JSONObject field = createTextField(key, titleName, visible);
|
|
|
|
|
+ JSONArray children = new JSONArray();
|
|
|
|
|
+ for (int i = 0; i < subKeys.length; i++) {
|
|
|
|
|
+ JSONObject child = new JSONObject();
|
|
|
|
|
+ child.put("key", subKeys[i]);
|
|
|
|
|
+ child.put("titleName", subTitles[i]);
|
|
|
|
|
+ child.put("visible", subVisible[i]);
|
|
|
|
|
+ children.add(child);
|
|
|
|
|
+ }
|
|
|
|
|
+ field.put("children", children);
|
|
|
|
|
+ return field;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|