diff --git a/mt-pay/database/customer_order_schema.sql b/mt-pay/database/customer_order_schema.sql deleted file mode 100644 index 335fca0..0000000 --- a/mt-pay/database/customer_order_schema.sql +++ /dev/null @@ -1,43 +0,0 @@ -CREATE TABLE `customer_order` ( - `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID', - `order_no` VARCHAR(64) NOT NULL UNIQUE COMMENT '订单号(全局唯一)', - `product_id` BIGINT NOT NULL COMMENT '商品ID', - `product_name` VARCHAR(500) NOT NULL COMMENT '商品名称', - `sku_id` BIGINT NOT NULL COMMENT 'SKU ID', - `sku_name` VARCHAR(500) NOT NULL COMMENT 'SKU名称/描述', - `quantity` INT NOT NULL COMMENT '购买数量', - `unit_price` DECIMAL(10, 2) NOT NULL COMMENT '单价', - `total_amount` DECIMAL(10, 2) NOT NULL COMMENT '订单总金额', - `currency` VARCHAR(3) NOT NULL COMMENT '货币代码', - `status` VARCHAR(20) NOT NULL DEFAULT 'PENDING' COMMENT '订单状态:PENDING-待支付,PAID-已支付,SHIPPED-已发货,COMPLETED-已完成,CANCELLED-已取消', - - -- 客户信息 - `customer_name` VARCHAR(100) NOT NULL COMMENT '客户姓名', - `customer_phone` VARCHAR(20) NOT NULL COMMENT '客户电话', - `customer_email` VARCHAR(100) COMMENT '客户邮箱', - - -- 收货地址 - `shipping_name` VARCHAR(100) NOT NULL COMMENT '收货人姓名', - `shipping_phone` VARCHAR(20) NOT NULL COMMENT '收货人电话', - `shipping_country` VARCHAR(50) NOT NULL COMMENT '收货国家', - `shipping_state` VARCHAR(50) COMMENT '收货州/省', - `shipping_city` VARCHAR(50) NOT NULL COMMENT '收货城市', - `shipping_street` VARCHAR(200) NOT NULL COMMENT '收货街道地址', - `shipping_postcode` VARCHAR(20) COMMENT '收货邮编', - - -- 支付信息 - `payment_order_id` BIGINT COMMENT '关联的支付订单ID', - `payment_status` VARCHAR(20) DEFAULT 'UNPAID' COMMENT '支付状态:UNPAID-未支付,PAID-已支付,FAILED-支付失败', - - -- 备注 - `remark` VARCHAR(500) COMMENT '订单备注', - - `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - PRIMARY KEY (`id`), - KEY `idx_order_no` (`order_no`), - KEY `idx_product_id` (`product_id`), - KEY `idx_status` (`status`), - KEY `idx_create_time` (`create_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='客户订单表'; - diff --git a/mt-pay/pom.xml b/mt-pay/pom.xml index 54faaa0..8abe3eb 100644 --- a/mt-pay/pom.xml +++ b/mt-pay/pom.xml @@ -145,6 +145,7 @@ org.springframework.boot spring-boot-maven-plugin + boot org.projectlombok diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/config/AliyunOSSProperties.java b/mt-pay/src/main/java/com/mtkj/mtpay/config/AliyunOSSProperties.java index 610538c..b069244 100644 --- a/mt-pay/src/main/java/com/mtkj/mtpay/config/AliyunOSSProperties.java +++ b/mt-pay/src/main/java/com/mtkj/mtpay/config/AliyunOSSProperties.java @@ -2,13 +2,12 @@ package com.mtkj.mtpay.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; /** * 阿里云OSS配置属性 + * 注意:不使用 @Component,而是通过 @EnableConfigurationProperties 在启动类中启用 */ @Data -@Component @ConfigurationProperties(prefix = "aliyun.oss") public class AliyunOSSProperties { diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/config/PingPongProperties.java b/mt-pay/src/main/java/com/mtkj/mtpay/config/PingPongProperties.java index e0beeb3..3e000b2 100644 --- a/mt-pay/src/main/java/com/mtkj/mtpay/config/PingPongProperties.java +++ b/mt-pay/src/main/java/com/mtkj/mtpay/config/PingPongProperties.java @@ -2,13 +2,12 @@ package com.mtkj.mtpay.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; /** * PingPong支付配置属性 + * 注意:不使用 @Component,而是通过 @EnableConfigurationProperties 在启动类中启用 */ @Data -@Component @ConfigurationProperties(prefix = "pingpong") public class PingPongProperties { diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/controller/PaymentController.java b/mt-pay/src/main/java/com/mtkj/mtpay/controller/PaymentController.java index 192d7da..0f04287 100644 --- a/mt-pay/src/main/java/com/mtkj/mtpay/controller/PaymentController.java +++ b/mt-pay/src/main/java/com/mtkj/mtpay/controller/PaymentController.java @@ -16,11 +16,15 @@ import java.util.Map; import java.util.Optional; /** - * 支付控制器 + * 支付控制器(PingPong支付) + * + * @deprecated 系统已切换到 PayPal 支付,此控制器保留以备将来需要时使用 + * 如需重新启用,请取消注释 @RestController 和 @RequestMapping 注解 */ +@Deprecated @Slf4j -@RestController -@RequestMapping("/api/payment") +// @RestController +// @RequestMapping("/api/payment") @RequiredArgsConstructor public class PaymentController { diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/service/impl/CustomerOrderServiceImpl.java b/mt-pay/src/main/java/com/mtkj/mtpay/service/impl/CustomerOrderServiceImpl.java index bbcbb4c..6761fdc 100644 --- a/mt-pay/src/main/java/com/mtkj/mtpay/service/impl/CustomerOrderServiceImpl.java +++ b/mt-pay/src/main/java/com/mtkj/mtpay/service/impl/CustomerOrderServiceImpl.java @@ -71,8 +71,30 @@ public class CustomerOrderServiceImpl implements CustomerOrderService { CustomerOrder order = new CustomerOrder(); order.setOrderNo(OrderIdGenerator.generateMerchantTransactionId()); order.setProductId(request.getProductId()); - order.setProductName(product.getName()); + + // 根据SKU的货币代码翻译商品名称并存入订单表 + String currency = sku.getCurrency(); + String translatedProductName = product.getName(); // 默认使用原始名称 + if (currency != null && !currency.trim().isEmpty()) { + try { + String targetLanguage = baiduTranslatorUtils.getLanguageByCurrency(currency); + log.debug("订单货币: {}, 推断目标语言: {}, 原始商品名称: {}", + currency, targetLanguage, product.getName()); + String translated = baiduTranslatorUtils.getTransResult(product.getName(), targetLanguage); + if (translated != null && !translated.equals(product.getName())) { + translatedProductName = translated; + log.info("商品名称翻译: {} -> {} (货币: {}, 语言: {})", + product.getName(), translatedProductName, currency, targetLanguage); + } + } catch (Exception e) { + log.warn("翻译商品名称失败,使用原始名称,商品ID: {}, 货币: {}", + request.getProductId(), currency, e); + } + } + order.setProductName(translatedProductName); + order.setSkuId(request.getSkuId()); + // SKU名称已在创建商品时翻译并存入数据库,直接使用即可 order.setSkuName(sku.getSku()); order.setQuantity(request.getQuantity()); order.setUnitPrice(sku.getPrice()); @@ -161,8 +183,7 @@ public class CustomerOrderServiceImpl implements CustomerOrderService { // 将JSON特殊字段转换为Map response.setShippingSpecialFields(order.getShippingSpecialFieldsMap()); - // 翻译订单内容(商品名称和SKU名称) - translateOrderContent(response); + // 注意:商品名称和SKU名称已在创建时翻译并存入数据库,查询时直接返回即可 return response; } @@ -185,8 +206,7 @@ public class CustomerOrderServiceImpl implements CustomerOrderService { // 将JSON特殊字段转换为Map response.setShippingSpecialFields(order.getShippingSpecialFieldsMap()); - // 翻译订单内容(商品名称和SKU名称) - translateOrderContent(response); + // 注意:商品名称和SKU名称已在创建时翻译并存入数据库,查询时直接返回即可 return response; } @@ -207,8 +227,7 @@ public class CustomerOrderServiceImpl implements CustomerOrderService { // 将JSON特殊字段转换为Map response.setShippingSpecialFields(order.getShippingSpecialFieldsMap()); - // 翻译订单内容(商品名称和SKU名称) - translateOrderContent(response); + // 注意:商品名称和SKU名称已在创建时翻译并存入数据库,查询时直接返回即可 return response; } @@ -288,47 +307,5 @@ public class CustomerOrderServiceImpl implements CustomerOrderService { log.info("订单状态更新成功,订单号: {}", orderNo); } - /** - * 翻译订单内容(商品名称和SKU名称) - * 根据订单的货币代码推断目标语言 - */ - private void translateOrderContent(CustomerOrderResponseDTO orderDTO) { - try { - // 如果没有货币信息,不进行翻译 - String currency = orderDTO.getCurrency(); - if (currency == null || currency.trim().isEmpty()) { - // 尝试使用支付货币 - currency = orderDTO.getPaymentCurrency(); - if (currency == null || currency.trim().isEmpty()) { - log.debug("订单货币代码为空,跳过翻译,订单号: {}", orderDTO.getOrderNo()); - return; - } - } - - String targetLanguage = baiduTranslatorUtils.getLanguageByCurrency(currency); - log.debug("根据货币代码 {} 推断目标语言: {}, 订单号: {}", currency, targetLanguage, orderDTO.getOrderNo()); - - // 翻译商品名称 - if (orderDTO.getProductName() != null && !orderDTO.getProductName().trim().isEmpty()) { - String translatedName = baiduTranslatorUtils.getTransResult(orderDTO.getProductName(), targetLanguage); - if (translatedName != null && !translatedName.equals(orderDTO.getProductName())) { - log.debug("商品名称翻译: {} -> {}, 订单号: {}", orderDTO.getProductName(), translatedName, orderDTO.getOrderNo()); - orderDTO.setProductName(translatedName); - } - } - - // 翻译SKU名称 - if (orderDTO.getSkuName() != null && !orderDTO.getSkuName().trim().isEmpty()) { - String translatedSku = baiduTranslatorUtils.getTransResult(orderDTO.getSkuName(), targetLanguage); - if (translatedSku != null && !translatedSku.equals(orderDTO.getSkuName())) { - log.debug("SKU名称翻译: {} -> {}, 订单号: {}", orderDTO.getSkuName(), translatedSku, orderDTO.getOrderNo()); - orderDTO.setSkuName(translatedSku); - } - } - } catch (Exception e) { - log.error("翻译订单内容失败,订单号: {}", orderDTO.getOrderNo(), e); - // 翻译失败不影响订单数据返回,只记录日志 - } - } } diff --git a/mt-pay/src/main/java/com/mtkj/mtpay/service/impl/ProductServiceImpl.java b/mt-pay/src/main/java/com/mtkj/mtpay/service/impl/ProductServiceImpl.java index 63401ed..470583b 100644 --- a/mt-pay/src/main/java/com/mtkj/mtpay/service/impl/ProductServiceImpl.java +++ b/mt-pay/src/main/java/com/mtkj/mtpay/service/impl/ProductServiceImpl.java @@ -70,6 +70,7 @@ public class ProductServiceImpl implements ProductService { // 创建商品 MtProduct product = new MtProduct(); + // 商品名称存储原始名称(不翻译,因为一个商品可能对应多个国家/货币) product.setName(request.getName()); product.setPrice(request.getPrice()); @@ -102,13 +103,34 @@ public class ProductServiceImpl implements ProductService { } log.debug("商品基础信息插入成功,商品ID: {}", product.getId()); - // 创建SKU + // 创建SKU(在存入数据库前完成翻译) if (request.getSkus() != null && !request.getSkus().isEmpty()) { log.debug("开始创建SKU,数量: {}", request.getSkus().size()); for (CreateProductRequestDTO.CreateProductSkuDTO skuDTO : request.getSkus()) { MtProductSku sku = new MtProductSku(); sku.setProductId(product.getId()); - sku.setSku(skuDTO.getSku()); + + // 根据SKU的货币代码推断目标语言并翻译SKU名称 + String currency = skuDTO.getCurrency(); + if (currency != null && !currency.trim().isEmpty()) { + String targetLanguage = baiduTranslatorUtils.getLanguageByCurrency(currency); + log.debug("SKU货币: {}, 推断目标语言: {}, 原始SKU名称: {}", + currency, targetLanguage, skuDTO.getSku()); + + // 翻译SKU名称 + String originalSkuName = skuDTO.getSku(); + String translatedSkuName = baiduTranslatorUtils.getTransResult(originalSkuName, targetLanguage); + if (translatedSkuName != null && !translatedSkuName.equals(originalSkuName)) { + log.info("SKU名称翻译: {} -> {} (货币: {}, 语言: {})", + originalSkuName, translatedSkuName, currency, targetLanguage); + sku.setSku(translatedSkuName); // 存储翻译后的名称 + } else { + sku.setSku(originalSkuName); // 翻译失败或无需翻译,使用原文 + } + } else { + sku.setSku(skuDTO.getSku()); // 无货币信息,使用原文 + } + sku.setPrice(skuDTO.getPrice()); sku.setCurrency(skuDTO.getCurrency()); sku.setStock(skuDTO.getStock()); @@ -125,7 +147,7 @@ public class ProductServiceImpl implements ProductService { throw new BusinessException(ResultCode.SYSTEM_ERROR, "创建SKU失败"); } log.debug("SKU创建成功,商品ID: {}, SKU编码: {}, SKU ID: {}", - product.getId(), skuDTO.getSku(), sku.getId()); + product.getId(), sku.getSku(), sku.getId()); } } @@ -207,8 +229,8 @@ public class ProductServiceImpl implements ProductService { response.setSkus(skuDTOs); - // 翻译功能:根据SKU的货币代码推断目标语言并翻译 - translateProductContent(response); + // 注意:商品名称和SKU名称已在创建时翻译并存入数据库,查询时直接返回即可 + // 如果需要根据当前用户的语言再次翻译,可以在这里添加逻辑 log.info("获取商品详情成功,商品ID: {}, 商品名称: {}, SKU数量: {}, 主图数量: {}", id, product.getName(), skuDTOs.size(), @@ -314,8 +336,7 @@ public class ProductServiceImpl implements ProductService { }).collect(Collectors.toList()); dto.setSkus(skuDTOs); - // 翻译功能:根据SKU的货币代码推断目标语言并翻译 - translateProductContent(dto); + // 注意:商品名称和SKU名称已在创建时翻译并存入数据库,查询时直接返回即可 result.add(dto); } @@ -324,58 +345,5 @@ public class ProductServiceImpl implements ProductService { return result; } - /** - * 翻译商品内容(商品名称和SKU名称) - * 根据SKU的货币代码推断目标语言 - */ - private void translateProductContent(ProductResponseDTO productDTO) { - try { - // 如果没有SKU,不进行翻译 - if (productDTO.getSkus() == null || productDTO.getSkus().isEmpty()) { - return; - } - - // 根据第一个SKU的货币代码推断目标语言 - String firstCurrency = productDTO.getSkus().get(0).getCurrency(); - if (firstCurrency == null || firstCurrency.trim().isEmpty()) { - log.debug("SKU货币代码为空,跳过翻译,商品ID: {}", productDTO.getId()); - return; - } - - String targetLanguage = baiduTranslatorUtils.getLanguageByCurrency(firstCurrency); - log.debug("根据货币代码 {} 推断目标语言: {}, 商品ID: {}", firstCurrency, targetLanguage, productDTO.getId()); - - // 翻译商品名称 - if (productDTO.getName() != null && !productDTO.getName().trim().isEmpty()) { - String translatedName = baiduTranslatorUtils.getTransResult(productDTO.getName(), targetLanguage); - if (translatedName != null && !translatedName.equals(productDTO.getName())) { - log.debug("商品名称翻译: {} -> {}, 商品ID: {}", productDTO.getName(), translatedName, productDTO.getId()); - productDTO.setName(translatedName); - } - } - - // 翻译每个SKU的名称(sku字段) - for (ProductResponseDTO.ProductSkuResponseDTO skuDTO : productDTO.getSkus()) { - // 如果SKU的货币与第一个不同,使用该SKU的货币推断语言 - String skuCurrency = skuDTO.getCurrency(); - String skuLanguage = targetLanguage; - if (skuCurrency != null && !skuCurrency.equals(firstCurrency)) { - skuLanguage = baiduTranslatorUtils.getLanguageByCurrency(skuCurrency); - } - - // 翻译SKU名称 - if (skuDTO.getSku() != null && !skuDTO.getSku().trim().isEmpty()) { - String translatedSku = baiduTranslatorUtils.getTransResult(skuDTO.getSku(), skuLanguage); - if (translatedSku != null && !translatedSku.equals(skuDTO.getSku())) { - log.debug("SKU名称翻译: {} -> {}, SKU ID: {}", skuDTO.getSku(), translatedSku, skuDTO.getId()); - skuDTO.setSku(translatedSku); - } - } - } - } catch (Exception e) { - log.error("翻译商品内容失败,商品ID: {}", productDTO.getId(), e); - // 翻译失败不影响商品数据返回,只记录日志 - } - } } diff --git a/mt-startup/src/main/java/com/mtkj/mtkjpay/MtkjpayApplication.java b/mt-startup/src/main/java/com/mtkj/mtkjpay/MtkjpayApplication.java index 385c5eb..9a2bf58 100644 --- a/mt-startup/src/main/java/com/mtkj/mtkjpay/MtkjpayApplication.java +++ b/mt-startup/src/main/java/com/mtkj/mtkjpay/MtkjpayApplication.java @@ -1,8 +1,12 @@ package com.mtkj.mtkjpay; +import com.mtkj.mtpay.config.AliyunOSSProperties; +import com.mtkj.mtpay.config.BaiduTranslatorConfig; +import com.mtkj.mtpay.config.PingPongProperties; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.core.env.Environment; /** @@ -16,6 +20,11 @@ import org.springframework.core.env.Environment; com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure.class } ) +@EnableConfigurationProperties({ + PingPongProperties.class, + BaiduTranslatorConfig.class, + AliyunOSSProperties.class +}) public class MtkjpayApplication { public static void main(String[] args) { diff --git a/mt-startup/src/main/resources/application-dev.yml b/mt-startup/src/main/resources/application-dev.yml index a24bad5..b7e7399 100644 --- a/mt-startup/src/main/resources/application-dev.yml +++ b/mt-startup/src/main/resources/application-dev.yml @@ -60,8 +60,65 @@ spring: config: multi-statement-allow: true +# 服务器配置(所有环境通用) +server: + port: 8082 + servlet: + context-path: / + # 文件上传配置 + multipart: + # 单个文件最大大小(10MB) + max-file-size: 10MB + # 请求最大大小(50MB,支持多文件上传) + max-request-size: 50MB + # 文件写入磁盘的阈值(超过此大小会写入临时文件) + file-size-threshold: 2MB + +# 应用配置(所有环境通用) +app: + # 前端访问地址(用于生成商品详情页URL等) + frontend: + url: http://localhost:3000 + +# 阿里云OSS相关配置(所有环境通用) +aliyun: + oss: + accessId: LTAI5tHbwvzWfANvNxju2yN1 + accessKey: sAQR2swByBgmMOofH97hSJT638aVcJ + endpoint: https://oss-cn-hangzhou.aliyuncs.com + bucketName: mtkj2025 + # PingPong支付配置(开发环境使用沙箱) pingpong: + client-id: your-client-id + acc-id: your-acc-id + secret: your-secret-key + sign-type: MD5 gateway: https://sandbox-acquirer-payment.pingpongx.com mode: sandbox + enabled: false + +# PayPal支付配置(开发环境使用沙箱) +paypal: + # PayPal Client ID(API密钥) + client-id: AdGYUZpvLuHR30dybOApvM-RNB1pVKtd74SVfh-6TK52xV-1JEBddHVMCWuDdyyHri4DXd4kABBi7Icb + # PayPal Client Secret(密钥) + client-secret: ENblspyRmwsOU_PWFurlhEYUF5Da6aYKl0pjK4ehm7p3R5aSqvbpaF_YsIIs8v0ty1c9WJu15XP-Fe_1 + # 环境模式:sandbox(沙箱)或 production(生产) + mode: sandbox + # 是否启用PayPal支付 + enabled: true + +# 百度翻译配置 +baidu: + translator: + app-id: 20250909002450241 + securityKey: o08lOpCcarl4Pb0BGdkq + transApiHost: https://fanyi-api.baidu.com/api/trans/vip/translate + qianfan: + app-key: ALTAKUyxxqjXU9YhPNYXj8zFQ2 + app-secret: 2c43ca701e1641b0a945a3a65125c143 + app_id: 9ae03450-0036-4c61-93bc-659a95cea443 + Authorization: Bearer bce-v3/ALTAK-9pcPkK0ZLYIDyDJNtVwji/f32d29d61a86e6e4e8c60d5297a310538b3920a7 + url: https://qianfan.baidubce.com/v2/app/conversation/runs diff --git a/mt-startup/src/main/resources/application.yml b/mt-startup/src/main/resources/application.yml index c486646..92b1a0b 100644 --- a/mt-startup/src/main/resources/application.yml +++ b/mt-startup/src/main/resources/application.yml @@ -61,17 +61,7 @@ spring: # 逻辑未删除值 logic-not-delete-value: 0 -# PingPong支付配置 -pingpong: - client-id: your-client-id - acc-id: your-acc-id - secret: your-secret-key - sign-type: MD5 - gateway: https://sandbox-acquirer-payment.pingpongx.com - mode: sandbox - enabled: true - -# 服务器配置 +# 服务器配置(所有环境通用) server: port: 8082 servlet: @@ -85,13 +75,13 @@ server: # 文件写入磁盘的阈值(超过此大小会写入临时文件) file-size-threshold: 2MB -# 应用配置 +# 应用配置(所有环境通用) app: # 前端访问地址(用于生成商品详情页URL等) frontend: url: http://localhost:3000 -# 阿里云OSS相关配置 +# 阿里云OSS相关配置(所有环境通用) aliyun: oss: accessId: LTAI5tHbwvzWfANvNxju2yN1