package com.talentcard.server.business.admin; import static org.assertj.core.api.Assertions.assertThat; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.UUID; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.context.ActiveProfiles; import org.springframework.transaction.annotation.Transactional; @SpringBootTest @ActiveProfiles("test") @Transactional class PremiumServiceMerchantTypeTests { @Autowired private JdbcTemplate jdbc; @Autowired private AdminBusinessService service; @ParameterizedTest @CsvSource({ "children, 子女托管, CHILD_ENTRUSTMENT", "approval, 行政审批, ADMIN_APPROVAL", "employment, 配偶推荐就业, SPOUSE_EMPLOYMENT" }) void migratedTypeAgreesAcrossListFiltersDetailAndEditing(String code, String label, String businessType) throws Exception { long id = insertMerchant("service", "other", 0); insertMapping(id, code, businessType, 0); migrate(); Map detail = service.merchant(id); assertThat(detail).containsEntry("merchantType", label).containsEntry("merchantTypeCode", code); String name = (String) detail.get("merchantName"); assertList(id, name, null, code, label, 1); assertList(id, name, label, code, label, 1); assertList(id, name, code, code, label, 1); assertList(id, name, "food", code, label, 0); // The edit page submits the display name returned by the detail endpoint. Map saved = service.updateMerchant(id, new MerchantUpdateRequest( name + " edited", (String) detail.get("merchantType"), "Test contact", "13800000000", "Test address", null, null, "营业中", (byte) 0, 0, (byte) 1, null, null, (byte) 0, null, null, null, null, null, null, null, (byte) 0, null, null)); assertThat(saved).containsEntry("merchantType", label).containsEntry("merchantTypeCode", code); assertThat(jdbc.queryForMap( "select category_key, business_type, deleted from premium_topic_merchant where merchant_id = ?", id)) .containsEntry("category_key", code).containsEntry("business_type", businessType); assertThat(jdbc.queryForObject( "select deleted from premium_topic_merchant where merchant_id = ?", Integer.class, id)).isZero(); assertList(id, name + " edited", label, code, label, 1); // Reapplying the repair must also preserve a subsequent explicit type edit. jdbc.update("update merchant set merchant_type = '餐饮服务', merchant_type_code = 'food' where id = ?", id); migrate(); assertThat(service.merchant(id)) .containsEntry("merchantType", "餐饮服务").containsEntry("merchantTypeCode", "food"); } @Test void repairIsIdempotentAndLeavesUnrelatedOrDeletedRecordsUntouched() throws Exception { long fixed = insertMerchant("service", "other", 0); insertMapping(fixed, "children", "CHILD_ENTRUSTMENT", 0); long unmapped = insertMerchant("service", "other", 0); long deletedMerchant = insertMerchant("service", "other", 1); insertMapping(deletedMerchant, "children", "CHILD_ENTRUSTMENT", 0); long deletedMapping = insertMerchant("service", "other", 0); insertMapping(deletedMapping, "approval", "ADMIN_APPROVAL", 1); long unsupportedMapping = insertMerchant("service", "other", 0); insertMapping(unsupportedMapping, "finance", "FINANCE", 0); long explicitCode = insertMerchant("service", "food", 0); insertMapping(explicitCode, "employment", "SPOUSE_EMPLOYMENT", 0); long explicitName = insertMerchant("LOCAL_TEST", "other", 0); insertMapping(explicitName, "children", "CHILD_ENTRUSTMENT", 0); migrate(); Map repaired = jdbc.queryForMap("select * from merchant where id = ?", fixed); migrate(); assertThat(jdbc.queryForMap("select * from merchant where id = ?", fixed)).isEqualTo(repaired); assertType(fixed, "子女托管", "children"); for (long id : new long[]{unmapped, deletedMerchant, deletedMapping, unsupportedMapping}) { assertType(id, "service", "other"); } assertType(explicitCode, "service", "food"); assertType(explicitName, "LOCAL_TEST", "other"); } private void assertList(long id, String name, String filter, String code, String label, int expected) { var page = service.merchants(name, null, filter, null, null, null, null, 1, 10); assertThat(page.total()).isEqualTo(expected); assertThat(page.records()).hasSize(expected); if (expected == 1) { assertThat(page.records().get(0)) .containsEntry("id", id).containsEntry("merchantType", label).containsEntry("merchantTypeCode", code); } } private void assertType(long id, String label, String code) { assertThat(jdbc.queryForMap("select merchant_type, merchant_type_code from merchant where id = ?", id)) .containsEntry("merchant_type", label).containsEntry("merchant_type_code", code); } private long insertMerchant(String label, String code, int deleted) { jdbc.update(""" insert into merchant(merchant_name, merchant_type, merchant_type_code, address, deleted) values (?, ?, ?, 'Test address', ?) """, "premium-type-" + UUID.randomUUID(), label, code, deleted); return jdbc.queryForObject("select last_insert_id()", Long.class); } private void insertMapping(long id, String category, String businessType, int deleted) { jdbc.update(""" insert into premium_topic_merchant(merchant_id, category_key, business_type, deleted) values (?, ?, ?, ?) """, id, category, businessType, deleted); } private void migrate() throws Exception { jdbc.execute(new ClassPathResource("db/migration/V157__backfill_premium_service_merchant_types.sql") .getContentAsString(StandardCharsets.UTF_8)); } }