package com.starry.admin.api; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.starry.admin.common.apitest.ApiTestDataSeeder; import com.starry.admin.modules.custom.module.entity.PlayCustomGiftInfoEntity; import com.starry.admin.modules.custom.service.IPlayCustomGiftInfoService; import com.starry.admin.modules.order.module.constant.OrderConstant; import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity; import com.starry.admin.modules.shop.module.entity.PlayClerkGiftInfoEntity; import com.starry.admin.modules.shop.module.entity.PlayGiftInfoEntity; import com.starry.admin.modules.shop.service.IPlayClerkGiftInfoService; import com.starry.admin.modules.shop.service.IPlayGiftInfoService; import com.starry.admin.modules.withdraw.entity.EarningsLineEntity; import com.starry.admin.utils.SecurityUtils; import com.starry.common.constant.Constants; import com.starry.common.context.CustomSecurityContextHolder; import com.starry.common.utils.IdUtils; import java.math.BigDecimal; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; class WxCustomGiftOrderApiTest extends WxCustomOrderApiTestSupport { @Autowired private IPlayGiftInfoService playGiftInfoService; @Autowired private IPlayCustomGiftInfoService playCustomGiftInfoService; @Autowired private IPlayClerkGiftInfoService playClerkGiftInfoService; private final ObjectMapper objectMapper = new ObjectMapper(); @Test void giftOrderFailsWhenBalanceInsufficient() throws Exception { SecurityUtils.setTenantId(ApiTestDataSeeder.DEFAULT_TENANT_ID); String remark = "API gift insufficient " + IdUtils.getUuid(); try { setCustomerBalance(BigDecimal.ZERO); String customerToken = wxTokenService.createWxUserToken(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID); customUserInfoService.updateTokenById(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID, customerToken); String payload = "{" + "\"clerkId\":\"" + ApiTestDataSeeder.DEFAULT_CLERK_ID + "\"," + "\"giftId\":\"" + ApiTestDataSeeder.DEFAULT_GIFT_ID + "\"," + "\"giftQuantity\":1," + "\"weiChatCode\":\"apitest-customer-wx\"," + "\"remark\":\"" + remark + "\"" + "}"; mockMvc.perform(post("/wx/custom/order/gift") .header(USER_HEADER, DEFAULT_USER) .header(TENANT_HEADER, DEFAULT_TENANT) .header(Constants.CUSTOM_USER_LOGIN_TOKEN, Constants.TOKEN_PREFIX + customerToken) .contentType(MediaType.APPLICATION_JSON) .content(payload)) .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value(998)); ensureTenantContext(); long count = playOrderInfoService.lambdaQuery() .eq(PlayOrderInfoEntity::getPurchaserBy, ApiTestDataSeeder.DEFAULT_CUSTOMER_ID) .eq(PlayOrderInfoEntity::getRemark, remark) .count(); Assertions.assertThat(count).isZero(); } finally { CustomSecurityContextHolder.remove(); } } @Test // 测试用例:用户余额充足且携带有效登录态时,请求 /wx/custom/order/gift 下单指定礼物, // 期望生成已完成的礼物奖励订单、产生对应收益记录,同时校验用户/陪玩师礼物计数与账户余额随订单金额同步更新。 void giftOrderCreatesCompletedRewardAndUpdatesGiftCounters__covers_CUS_005() throws Exception { SecurityUtils.setTenantId(ApiTestDataSeeder.DEFAULT_TENANT_ID); try { resetCustomerBalance(); String customerToken = wxTokenService.createWxUserToken(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID); customUserInfoService.updateTokenById(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID, customerToken); PlayGiftInfoEntity gift = playGiftInfoService.selectPlayGiftInfoById(ApiTestDataSeeder.DEFAULT_GIFT_ID); Assertions.assertThat(gift).as("seeded gift should exist").isNotNull(); int giftQuantity = 2; String remark = "API gift order " + IdUtils.getUuid(); BigDecimal totalAmount = gift.getPrice().multiply(BigDecimal.valueOf(giftQuantity)); BigDecimal initialBalance = customUserInfoService.getById(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID).getAccountBalance(); String payload = "{" + "\"clerkId\":\"" + ApiTestDataSeeder.DEFAULT_CLERK_ID + "\"," + "\"giftId\":\"" + ApiTestDataSeeder.DEFAULT_GIFT_ID + "\"," + "\"giftQuantity\":" + giftQuantity + "," + "\"weiChatCode\":\"apitest-customer-wx\"," + "\"remark\":\"" + remark + "\"" + "}"; String response = mockMvc.perform(post("/wx/custom/order/gift") .header(USER_HEADER, DEFAULT_USER) .header(TENANT_HEADER, DEFAULT_TENANT) .header(Constants.CUSTOM_USER_LOGIN_TOKEN, Constants.TOKEN_PREFIX + customerToken) .contentType(MediaType.APPLICATION_JSON) .content(payload)) .andExpect(status().isOk()) .andExpect(jsonPath("$.code").value(200)) .andExpect(jsonPath("$.data").isNotEmpty()) .andReturn() .getResponse() .getContentAsString(); JsonNode root = objectMapper.readTree(response); String orderId = root.path("data").asText(); ensureTenantContext(); PlayOrderInfoEntity order = playOrderInfoService.selectOrderInfoById(orderId); Assertions.assertThat(order).isNotNull(); Assertions.assertThat(order.getRemark()).isEqualTo(remark); Assertions.assertThat(order.getOrderStatus()).isEqualTo(OrderConstant.OrderStatus.COMPLETED.getCode()); Assertions.assertThat(order.getPlaceType()).isEqualTo(OrderConstant.PlaceType.REWARD.getCode()); Assertions.assertThat(order.getRewardType()).isEqualTo(OrderConstant.RewardType.GIFT.getCode()); Assertions.assertThat(order.getFinalAmount()).isEqualByComparingTo(totalAmount); ensureTenantContext(); long earningsCount = earningsService.lambdaQuery() .eq(EarningsLineEntity::getOrderId, orderId) .count(); Assertions.assertThat(earningsCount).isEqualTo(1); ensureTenantContext(); PlayCustomGiftInfoEntity customerGift = playCustomGiftInfoService.lambdaQuery() .eq(PlayCustomGiftInfoEntity::getCustomId, ApiTestDataSeeder.DEFAULT_CUSTOMER_ID) .eq(PlayCustomGiftInfoEntity::getGiffId, ApiTestDataSeeder.DEFAULT_GIFT_ID) .one(); Assertions.assertThat(customerGift).isNotNull(); Assertions.assertThat(customerGift.getGiffNumber()).isEqualTo((long) giftQuantity); ensureTenantContext(); PlayClerkGiftInfoEntity clerkGift = playClerkGiftInfoService.lambdaQuery() .eq(PlayClerkGiftInfoEntity::getClerkId, ApiTestDataSeeder.DEFAULT_CLERK_ID) .eq(PlayClerkGiftInfoEntity::getGiffId, ApiTestDataSeeder.DEFAULT_GIFT_ID) .one(); Assertions.assertThat(clerkGift).isNotNull(); Assertions.assertThat(clerkGift.getGiffNumber()).isEqualTo((long) giftQuantity); ensureTenantContext(); BigDecimal finalBalance = customUserInfoService.getById(ApiTestDataSeeder.DEFAULT_CUSTOMER_ID) .getAccountBalance(); Assertions.assertThat(finalBalance).isEqualByComparingTo(initialBalance.subtract(totalAmount)); } finally { CustomSecurityContextHolder.remove(); } } }