1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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<String, Object> 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<String, Object> 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<String, Object> 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));
    }
}