| | |
| | | if (isInvalidShareRatio(partner.getServiceShareRatio())) { |
| | | return AjaxResult.error("服务费分成比例必须为0-100且最多两位小数"); |
| | | } |
| | | if (partner.getElectricityShareRatio() != null || partner.getServiceShareRatio() != null) { |
| | | if (StringUtils.isEmpty(partner.getIcbcSubMerId())) { |
| | | return AjaxResult.error("填写分成比例时工行二级商户编号不能为空"); |
| | | } |
| | | if (StringUtils.isEmpty(partner.getIcbcSubMerPrtclNo())) { |
| | | return AjaxResult.error("填写分成比例时工行二级商户协议编号不能为空"); |
| | | } |
| | | } |
| | | return AjaxResult.success(); |
| | | } |
| | | |
| New file |
| | |
| | | package com.ruoyi.chargingPile.controller; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| | | import com.ruoyi.chargingPile.api.model.Site; |
| | | import com.ruoyi.chargingPile.service.ISiteService; |
| | | import com.ruoyi.common.core.constant.Constants; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.test.util.ReflectionTestUtils; |
| | | |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.junit.jupiter.api.Assertions.assertNotNull; |
| | | import static org.junit.jupiter.api.Assertions.assertTrue; |
| | | import static org.mockito.ArgumentMatchers.any; |
| | | import static org.mockito.Mockito.mock; |
| | | import static org.mockito.Mockito.never; |
| | | import static org.mockito.Mockito.verify; |
| | | import static org.mockito.Mockito.when; |
| | | |
| | | class SiteControllerTest { |
| | | |
| | | @Test |
| | | void getSiteByIdsReturnsEmptyListWithoutQueryingWhenIdsAreEmpty() { |
| | | SiteController controller = new SiteController(); |
| | | ISiteService siteService = mock(ISiteService.class); |
| | | when(siteService.list(any(Wrapper.class))).thenThrow(new AssertionError("empty ids must not query database")); |
| | | ReflectionTestUtils.setField(controller, "siteService", siteService); |
| | | |
| | | R<List<Site>> result = controller.getSiteByIds(Collections.emptyList()); |
| | | |
| | | assertEquals(Constants.SUCCESS, result.getCode()); |
| | | assertNotNull(result.getData()); |
| | | assertTrue(result.getData().isEmpty()); |
| | | verify(siteService, never()).list(any(Wrapper.class)); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.chargingPile.service.impl; |
| | | |
| | | import com.ruoyi.chargingPile.api.model.Partner; |
| | | import org.junit.jupiter.api.Test; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertTrue; |
| | | |
| | | class PartnerServiceImplTest { |
| | | |
| | | @Test |
| | | void acceptsShareRatioWithoutIcbcSubMerchantConfiguration() { |
| | | Partner partner = new Partner(); |
| | | partner.setId(1); |
| | | partner.setCode("PARTNER001"); |
| | | partner.setName("测试合作商"); |
| | | partner.setPartnerType(1); |
| | | partner.setPhoneOne("13800000000"); |
| | | partner.setElectricityShareRatio(new BigDecimal("20.00")); |
| | | partner.setServiceShareRatio(new BigDecimal("30.00")); |
| | | |
| | | assertTrue(new PartnerServiceImpl().addPartnerParameterCheck(partner).isSuccess()); |
| | | } |
| | | } |
| | |
| | | List<IcbcAdminSubOrderVO> result = new ArrayList<>(); |
| | | for (TChargingOrderShareRecord record : records) { |
| | | IcbcAdminSubOrderVO item = buildIcbcAdminSubOrderVO(record); |
| | | if (!Boolean.TRUE.equals(record.getNeedOnlineShare())) { |
| | | item.setQueryStatus("SKIP"); |
| | | item.setErrorMessage(record.getFailReason()); |
| | | result.add(item); |
| | | continue; |
| | | } |
| | | try { |
| | | IcbcSubOrderQueryReq query = IcbcAdminFundOperationSupport.buildSubOrderQueryRequest(order, record); |
| | | item.applyQuery(requireFeignData(icbcPaymentClient.querySubOrder(query), "工行子订单查询失败")); |
| | |
| | | record.setElectricityShareAmount(electricityShareAmount); |
| | | record.setServiceShareAmount(serviceShareAmount); |
| | | record.setShareAmount(electricityShareAmount.add(serviceShareAmount).setScale(2, RoundingMode.HALF_UP)); |
| | | record.setNeedOnlineShare("ICBC".equals(payChannel) && record.getShareAmount().compareTo(BigDecimal.ZERO) > 0); |
| | | record.setOnlineShareStatus(Boolean.TRUE.equals(record.getNeedOnlineShare()) ? "INIT" : "RECORDED"); |
| | | if ("ICBC".equals(payChannel)) { |
| | | record.setSeqNo(chargingOrder.getCode()); |
| | | record.setBusiType("1"); |
| | |
| | | if ("ICBC".equals(payChannel) && partner != null) { |
| | | record.setSubMerId(partner.getIcbcSubMerId()); |
| | | record.setSubMerPrtclNo(partner.getIcbcSubMerPrtclNo()); |
| | | record.setMerAcct(partner.getIcbcMerAcct()); |
| | | } |
| | | boolean needOnlineShare = shouldProcessIcbcOnlineShare(payChannel, record.getShareAmount(), partner); |
| | | record.setNeedOnlineShare(needOnlineShare); |
| | | record.setOnlineShareStatus(needOnlineShare ? "INIT" : "RECORDED"); |
| | | if ("ICBC".equals(payChannel) && record.getShareAmount().compareTo(BigDecimal.ZERO) > 0 && !needOnlineShare) { |
| | | record.setFailReason("未配置完整工行二级商户参数,仅记录本地分账"); |
| | | } |
| | | record.setRetryCount(0); |
| | | record.setDelFlag(false); |
| | |
| | | return amount.multiply(ratio).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | static boolean shouldProcessIcbcOnlineShare(String payChannel, BigDecimal shareAmount, Partner partner) { |
| | | return "ICBC".equals(payChannel) |
| | | && shareAmount != null |
| | | && shareAmount.compareTo(BigDecimal.ZERO) > 0 |
| | | && partner != null |
| | | && StringUtils.hasLength(partner.getIcbcSubMerId()) |
| | | && StringUtils.hasLength(partner.getIcbcSubMerPrtclNo()); |
| | | } |
| | | |
| | | private IcbcSubOrderSplitReq buildIcbcSubOrderSplitReq(TChargingOrderShareRecord record) { |
| | | IcbcSubOrderSplitReq req = new IcbcSubOrderSplitReq(); |
| | | req.setChargingOrderCode(record.getChargingOrderCode()); |
| | |
| | | req.setSubMerId(record.getSubMerId()); |
| | | req.setSubMerPrtclNo(record.getSubMerPrtclNo()); |
| | | req.setClassifyAmt(record.getShareAmount()); |
| | | req.setMerAcct(record.getMerAcct()); |
| | | req.setMerSpInfor("充电订单分账:" + record.getChargingOrderCode()); |
| | | return req; |
| | | } |
| | |
| | | data.put("icbcPartnerId", partner.getIcbcPartnerId()); |
| | | data.put("icbcSubMerId", partner.getIcbcSubMerId()); |
| | | data.put("icbcSubMerPrtclNo", partner.getIcbcSubMerPrtclNo()); |
| | | data.put("icbcMerAcct", partner.getIcbcMerAcct()); |
| | | if (partner.getElectricityShareRatio() != null) { |
| | | data.put("electricityShareRatio", partner.getElectricityShareRatio()); |
| | | } |
| New file |
| | |
| | | package com.ruoyi.order.service.impl; |
| | | |
| | | import com.ruoyi.chargingPile.api.model.Partner; |
| | | import org.junit.jupiter.api.Test; |
| | | |
| | | import java.math.BigDecimal; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertFalse; |
| | | import static org.junit.jupiter.api.Assertions.assertTrue; |
| | | |
| | | class ChargingOrderShareConfigurationTest { |
| | | |
| | | @Test |
| | | void onlyEnablesIcbcOnlineShareWithCompleteSubMerchantConfiguration() { |
| | | Partner partner = new Partner(); |
| | | partner.setIcbcSubMerId("231011990055"); |
| | | |
| | | assertFalse(TChargingOrderServiceImpl.shouldProcessIcbcOnlineShare("ICBC", new BigDecimal("1.00"), partner)); |
| | | |
| | | partner.setIcbcSubMerPrtclNo("2310119900550201"); |
| | | assertTrue(TChargingOrderServiceImpl.shouldProcessIcbcOnlineShare("ICBC", new BigDecimal("1.00"), partner)); |
| | | assertFalse(TChargingOrderServiceImpl.shouldProcessIcbcOnlineShare("ICBC", BigDecimal.ZERO, partner)); |
| | | assertFalse(TChargingOrderServiceImpl.shouldProcessIcbcOnlineShare("BALANCE", new BigDecimal("1.00"), partner)); |
| | | } |
| | | } |
| New file |
| | |
| | | package com.ruoyi.payment.icbc.service.impl; |
| | | |
| | | import com.ruoyi.payment.icbc.config.IcbcPayProperties; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.test.util.ReflectionTestUtils; |
| | | |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertTrue; |
| | | |
| | | class IcbcPayServiceImplTest { |
| | | |
| | | @Test |
| | | void verifiesRealPaymentCallbackWithConfiguredNotifyPath() { |
| | | IcbcPayProperties properties = new IcbcPayProperties(); |
| | | properties.setCharset("UTF-8"); |
| | | properties.setSignType("RSA2"); |
| | | properties.setNotifyUrl("https://www.lyt18.cn/payment/icbc/callBack"); |
| | | properties.setIcbcPublicKey( |
| | | "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCMpjaWjngB4E3ATh+G1DVAmQnIpiPEFAEDqRfNGAVvvH35yDetqewKi0l7OEceTMN1C6NPym3zStvSoQayjYV+eIcZERkx31KhtFu9clZKgRTyPjdKMIth/wBtPKjL/5+PYalLdomM4ONthrPgnkN4x4R0+D4+EBpXo8gNiAFsNwIDAQAB"); |
| | | |
| | | Map<String, String> params = new HashMap<>(); |
| | | params.put("api", "/api/cardbusiness/aggregatepay/b2c/online/consumepurchase/V1"); |
| | | params.put("app_id", "11000000000000096526"); |
| | | params.put("biz_content", "{\"access_type\":\"9\",\"attach\":\"1\",\"bank_disc_amt\":\"0\",\"card_flag\":\"\",\"card_kind\":\"\",\"card_no\":\"\",\"coupon_amt\":\"0\",\"cust_id\":\"\",\"decr_flag\":\"\",\"ecoupon_amt\":\"0\",\"mer_disc_amt\":\"0\",\"mer_id\":\"231011990056\",\"msg_id\":\"050200106196883020737106827\",\"open_id\":\"ow8NuxGF2KZlxu2sOd_bD44hacJI\",\"order_id\":\"231011990056000552607150002085\",\"out_trade_no\":\"CD10920260715105437088\",\"pay_time\":\"20260715105446\",\"pay_type\":\"9\",\"payment_amt\":\"50\",\"point_amt\":\"0\",\"return_code\":\"0\",\"return_msg\":\"\u4ea4\u6613\u6210\u529f\",\"third_party_coupon_amt\":\"0\",\"third_party_discount_amt\":\"0\",\"third_trade_no\":\"4500000314202607153746388432\",\"total_amt\":\"50\",\"total_disc_amt\":\"0\"}"); |
| | | params.put("charset", "UTF-8"); |
| | | params.put("format", "json"); |
| | | params.put("from", "icbc-api"); |
| | | params.put("sign", "ImWNkGh6yx2UB40+bH+nNcqLDv1C8qyGnO/3FVw4wv9/AI53PEuIoTO22UlPg0lP4QJb6z25vJ4O5YVRxaT8pInGW00izoKArF2nOtWka7wEFWdnRVJ8vBNRZfQ5+bXR1lRc7lqQyNXIorFN79z3BY9bjVzSlbuQJPDweVCkV+o="); |
| | | params.put("sign_type", "RSA"); |
| | | params.put("timestamp", "2026-07-15 10:54:47"); |
| | | |
| | | IcbcPayServiceImpl service = new IcbcPayServiceImpl(); |
| | | ReflectionTestUtils.setField(service, "properties", properties); |
| | | |
| | | assertTrue(Boolean.TRUE.equals(ReflectionTestUtils.invokeMethod(service, "verifyNotify", params))); |
| | | } |
| | | } |