This commit is contained in:
van
2026-04-09 00:09:09 +08:00
parent c9876df3de
commit e94f17973c
50 changed files with 1637 additions and 72 deletions

View File

@@ -5,6 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
@@ -14,6 +15,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
*/
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@EnableScheduling
@EnableAsync
public class RuoYiApplication
{
public static void main(String[] args)

View File

@@ -1,22 +1,32 @@
package com.ruoyi.web.controller.common;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.erp.request.IERPAccount;
import com.ruoyi.jarvis.service.IErpGoofishOrderService;
import com.ruoyi.jarvis.service.erp.ErpAccountResolver;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* 开放平台回调接收端
* 注意:/product/receive 与 /order/receive 为示例路径,请在开放平台配置时使用你自己的正式回调地址
* 闲管家开放平台推送回调(请在开放平台填写真实 URL
* 订单:建议 POST .../open/callback/order/receive
*/
@Anonymous
@RestController
@RequestMapping("/open/callback")
public class OpenCallbackController extends BaseController {
public class OpenCallbackController {
@Resource
private ErpAccountResolver erpAccountResolver;
@Resource
private IErpGoofishOrderService erpGoofishOrderService;
@PostMapping("/product/receive")
public JSONObject receiveProductCallback(
@@ -25,7 +35,8 @@ public class OpenCallbackController extends BaseController {
@RequestParam("sign") String sign,
@RequestBody JSONObject body
) {
if (!verifySign(appid, timestamp, sign, body)) {
IERPAccount account = erpAccountResolver.resolveStrict(appid);
if (!verifySign(account, timestamp, sign, body)) {
JSONObject fail = new JSONObject();
fail.put("result", "fail");
fail.put("msg", "签名失败");
@@ -44,26 +55,33 @@ public class OpenCallbackController extends BaseController {
@RequestParam("sign") String sign,
@RequestBody JSONObject body
) {
if (!verifySign(appid, timestamp, sign, body)) {
IERPAccount account = erpAccountResolver.resolveStrict(appid);
if (!verifySign(account, timestamp, sign, body)) {
JSONObject fail = new JSONObject();
fail.put("result", "fail");
fail.put("msg", "签名失败");
return fail;
}
try {
erpGoofishOrderService.publishOrProcessNotify(appid, timestamp, body);
} catch (Exception e) {
JSONObject fail = new JSONObject();
fail.put("result", "fail");
fail.put("msg", "入队异常");
return fail;
}
JSONObject ok = new JSONObject();
ok.put("result", "success");
ok.put("msg", "接收成功");
return ok;
}
private boolean verifySign(String appid, Long timestamp, String sign, JSONObject body) {
// TODO: 这里需要根据appid查出对应的 appKey/appSecret
// 为了示例,直接使用 ERPAccount.ACCOUNT_HUGE 的常量。生产请替换为从数据库/配置读取
String appKey = "1016208368633221";
String appSecret = "waLiRMgFcixLbcLjUSSwo370Hp1nBcBu";
private boolean verifySign(IERPAccount account, Long timestamp, String sign, JSONObject body) {
if (account == null || StringUtils.isEmpty(sign)) {
return false;
}
String json = body == null ? "{}" : body.toJSONString();
String data = appKey + "," + md5(json) + "," + (timestamp == null ? 0 : timestamp) + "," + appSecret;
String data = account.getApiKey() + "," + md5(json) + "," + (timestamp == null ? 0 : timestamp) + "," + account.getApiKeySecret();
String local = md5(data);
return StringUtils.equalsIgnoreCase(local, sign);
}
@@ -82,5 +100,3 @@ public class OpenCallbackController extends BaseController {
}
}
}

View File

@@ -11,6 +11,10 @@ import com.ruoyi.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ruoyi.erp.request.ERPAccount;
import com.ruoyi.erp.request.IERPAccount;
import com.ruoyi.jarvis.domain.ErpOpenConfig;
import com.ruoyi.jarvis.service.IErpOpenConfigService;
import com.ruoyi.jarvis.service.erp.ErpAccountResolver;
import com.ruoyi.erp.request.ProductCreateRequest;
import com.ruoyi.erp.request.ProductCategoryListQueryRequest;
import com.ruoyi.erp.request.ProductPropertyListQueryRequest;
@@ -20,6 +24,7 @@ import com.ruoyi.erp.request.ProductDownShelfRequest;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.constraints.*;
import java.util.ArrayList;
import java.util.HashMap;
@@ -36,13 +41,19 @@ public class ProductController extends BaseController {
@Autowired
private IOuterIdGeneratorService outerIdGeneratorService;
@Resource
private ErpAccountResolver erpAccountResolver;
@Resource
private IErpOpenConfigService erpOpenConfigService;
private static final Logger log = LoggerFactory.getLogger(ProductController.class);
@PostMapping("/createByPromotion")
public R<?> createByPromotion(@RequestBody @Validated CreateProductFromPromotionRequest req) {
try {
ERPAccount account = resolveAccount(req.getAppid());
IERPAccount account = resolveAccount(req.getAppid());
// 1) 组装 ERPShop
ERPShop erpShop = new ERPShop();
erpShop.setChannelCatid(req.getChannelCatId());
@@ -143,7 +154,7 @@ public class ProductController extends BaseController {
@PostMapping("/publish")
public R<?> publish(@RequestBody @Validated PublishRequest req) {
try {
ERPAccount account = resolveAccount(req.getAppid());
IERPAccount account = resolveAccount(req.getAppid());
ProductPublishRequest publishRequest = new ProductPublishRequest(account);
publishRequest.setProductId(req.getProductId());
publishRequest.setUserName(req.getUserName());
@@ -344,10 +355,22 @@ public class ProductController extends BaseController {
String name = firstNonBlank(row.getString("user_name"), row.getString("xy_name"), row.getString("username"), row.getString("nick"));
if (name != null) {
String label = name;
for (ERPAccount a : ERPAccount.values()) {
if (name.equals(a.getXyName())) {
label = name + "(" + a.getRemark() + ")";
break;
List<ErpOpenConfig> cfgs = erpOpenConfigService.selectEnabledOrderBySort();
if (cfgs != null) {
for (ErpOpenConfig c : cfgs) {
if (name.equals(c.getXyUserName())) {
String r = c.getRemark() != null ? c.getRemark() : c.getAppKey();
label = name + "(" + r + ")";
break;
}
}
}
if (label.equals(name)) {
for (ERPAccount a : ERPAccount.values()) {
if (name.equals(a.getXyName())) {
label = name + "(" + a.getRemark() + ")";
break;
}
}
}
options.add(new Option(name, label));
@@ -376,20 +399,24 @@ public class ProductController extends BaseController {
@GetMapping("/ERPAccount")
public R<?> erpAccounts() {
java.util.List<Option> list = new java.util.ArrayList<>();
List<ErpOpenConfig> cfgs = erpOpenConfigService.selectEnabledOrderBySort();
if (cfgs != null) {
for (ErpOpenConfig c : cfgs) {
String label = StringUtils.isNotEmpty(c.getRemark()) ? c.getRemark() : c.getXyUserName();
if (StringUtils.isEmpty(label)) {
label = c.getAppKey();
}
list.add(new Option(c.getAppKey(), "【配置】" + label));
}
}
for (ERPAccount a : ERPAccount.values()) {
// 仅显示备注作为 labelvalue 仍为 appid
list.add(new Option(a.getApiKey(), a.getRemark()));
list.add(new Option(a.getApiKey(), "【内置】" + a.getRemark()));
}
return R.ok(list);
}
private ERPAccount resolveAccount(String appid) {
if (appid != null && !appid.isEmpty()) {
for (ERPAccount a : ERPAccount.values()) {
if (a.getApiKey().equals(appid)) return a;
}
}
return ERPAccount.ACCOUNT_HUGE;
private IERPAccount resolveAccount(String appid) {
return erpAccountResolver.resolve(appid);
}
/**
@@ -558,7 +585,7 @@ public class ProductController extends BaseController {
@PostMapping("/downShelf")
public R<?> downShelf(@RequestBody @Validated DownShelfRequest req) {
try {
ERPAccount account = resolveAccount(req.getAppid());
IERPAccount account = resolveAccount(req.getAppid());
ProductDownShelfRequest downShelfRequest = new ProductDownShelfRequest(account);
downShelfRequest.setProductId(req.getProductId());
String resp = downShelfRequest.getResponseBody();
@@ -576,7 +603,7 @@ public class ProductController extends BaseController {
@PostMapping("/batchPublish")
public R<?> batchPublish(@RequestBody @Validated BatchPublishRequest req) {
try {
ERPAccount account = resolveAccount(req.getAppid());
IERPAccount account = resolveAccount(req.getAppid());
List<Long> productIds = req.getProductIds();
if (productIds == null || productIds.isEmpty()) {
@@ -651,7 +678,7 @@ public class ProductController extends BaseController {
@PostMapping("/batchDownShelf")
public R<?> batchDownShelf(@RequestBody @Validated BatchDownShelfRequest req) {
try {
ERPAccount account = resolveAccount(req.getAppid());
IERPAccount account = resolveAccount(req.getAppid());
List<Long> productIds = req.getProductIds();
if (productIds == null || productIds.isEmpty()) {

View File

@@ -0,0 +1,82 @@
package com.ruoyi.web.controller.jarvis;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.jarvis.config.JarvisGoofishProperties;
import com.ruoyi.jarvis.domain.ErpGoofishOrder;
import com.ruoyi.jarvis.service.IErpGoofishOrderService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/jarvis/erpGoofishOrder")
public class ErpGoofishOrderController extends BaseController {
@Resource
private IErpGoofishOrderService erpGoofishOrderService;
@Resource
private JarvisGoofishProperties goofishProperties;
@PreAuthorize("@ss.hasPermi('jarvis:erpGoofishOrder:list')")
@GetMapping("/list")
public TableDataInfo list(ErpGoofishOrder query) {
startPage();
List<ErpGoofishOrder> list = erpGoofishOrderService.selectList(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('jarvis:erpGoofishOrder:query')")
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable Long id) {
return AjaxResult.success(erpGoofishOrderService.selectById(id));
}
@PreAuthorize("@ss.hasPermi('jarvis:erpGoofishOrder:edit')")
@Log(title = "闲管家拉单", businessType = BusinessType.OTHER)
@PostMapping("/pull/{appKey}")
public AjaxResult pullOne(@PathVariable String appKey, @RequestParam(value = "hours", required = false) Integer hours) {
int h = hours == null ? goofishProperties.getPullLookbackHours() : hours;
int n = erpGoofishOrderService.pullOrdersForAppKey(appKey, h);
Map<String, Object> data = new LinkedHashMap<>();
data.put("processedItems", n);
data.put("lookbackHours", h);
return AjaxResult.success(data);
}
@PreAuthorize("@ss.hasPermi('jarvis:erpGoofishOrder:edit')")
@Log(title = "闲管家全量拉单", businessType = BusinessType.OTHER)
@PostMapping("/pullAll")
public AjaxResult pullAll(@RequestParam(value = "hours", required = false) Integer hours) {
int h = hours == null ? goofishProperties.getPullLookbackHours() : hours;
int n = erpGoofishOrderService.pullAllEnabled(h);
Map<String, Object> data = new LinkedHashMap<>();
data.put("processedItems", n);
data.put("lookbackHours", h);
return AjaxResult.success(data);
}
@PreAuthorize("@ss.hasPermi('jarvis:erpGoofishOrder:edit')")
@Log(title = "闲管家订单详情刷新", businessType = BusinessType.UPDATE)
@PostMapping("/refreshDetail/{id}")
public AjaxResult refreshDetail(@PathVariable Long id) {
erpGoofishOrderService.refreshDetail(id);
return AjaxResult.success();
}
@PreAuthorize("@ss.hasPermi('jarvis:erpGoofishOrder:edit')")
@Log(title = "闲管家重试发货", businessType = BusinessType.UPDATE)
@PostMapping("/retryShip/{id}")
public AjaxResult retryShip(@PathVariable Long id) {
erpGoofishOrderService.retryShip(id);
return AjaxResult.success();
}
}

View File

@@ -0,0 +1,63 @@
package com.ruoyi.web.controller.jarvis;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.jarvis.domain.ErpOpenConfig;
import com.ruoyi.jarvis.service.IErpOpenConfigService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@RestController
@RequestMapping("/jarvis/erpOpenConfig")
public class ErpOpenConfigController extends BaseController {
@Resource
private IErpOpenConfigService erpOpenConfigService;
@PreAuthorize("@ss.hasPermi('jarvis:erpOpenConfig:list')")
@GetMapping("/list")
public TableDataInfo list(ErpOpenConfig query) {
startPage();
List<ErpOpenConfig> list = erpOpenConfigService.selectList(query);
return getDataTable(list);
}
@PreAuthorize("@ss.hasPermi('jarvis:erpOpenConfig:query')")
@GetMapping("/{id}")
public AjaxResult getInfo(@PathVariable Long id) {
return AjaxResult.success(erpOpenConfigService.selectById(id));
}
@PreAuthorize("@ss.hasPermi('jarvis:erpOpenConfig:add')")
@Log(title = "闲管家应用配置", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody ErpOpenConfig row) {
return toAjax(erpOpenConfigService.insert(row));
}
@PreAuthorize("@ss.hasPermi('jarvis:erpOpenConfig:edit')")
@Log(title = "闲管家应用配置", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody ErpOpenConfig row) {
return toAjax(erpOpenConfigService.update(row));
}
@PreAuthorize("@ss.hasPermi('jarvis:erpOpenConfig:remove')")
@Log(title = "闲管家应用配置", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids) {
int n = 0;
if (ids != null) {
for (Long id : ids) {
n += erpOpenConfigService.deleteById(id);
}
}
return toAjax(n);
}
}