package com.talentcard.server.mapper; import static org.assertj.core.api.Assertions.assertThat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; import javax.sql.DataSource; import org.apache.ibatis.mapping.Environment; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; public class MerchantSettlementStatisticsMapperTests { private SqlSessionFactory sessionFactory; @BeforeEach void setUp() { DriverManagerDataSource dataSource = new DriverManagerDataSource( "jdbc:h2:mem:merchant-settlement-statistics-" + System.nanoTime() + ";MODE=MySQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1", "sa", ""); createSchema(dataSource); insertFixture(dataSource); Environment environment = new Environment("test", new JdbcTransactionFactory(), dataSource); Configuration configuration = new Configuration(environment); configuration.addMapper(MerchantSettlementStatisticsMapper.class); sessionFactory = new SqlSessionFactoryBuilder().build(configuration); } @Test void includesHotelFreeOfflineSubsidyWithoutIncreasingTransactionAmount() { LocalDateTime start = LocalDate.now().atStartOfDay(); LocalDateTime end = LocalDate.now().plusDays(1).atStartOfDay(); try (SqlSession session = sessionFactory.openSession()) { MerchantSettlementStatisticsMapper mapper = session.getMapper(MerchantSettlementStatisticsMapper.class); List> summaries = mapper.selectPeriodSummaries( 88L, "HOTEL", "DAY", start, end, 20, 0); assertThat(summaries).hasSize(1); assertTotals(summaries.get(0)); assertThat(mapper.countPeriodSummaries(88L, "HOTEL", "DAY", start, end)).isEqualTo(1L); List> overview = mapper.selectMerchantOverviews(88L, "HOTEL", start, end); assertThat(overview).hasSize(1); assertTotals(overview.get(0)); Map cards = mapper.selectDashboardCards(88L, start, end, start, end); assertThat(longValue(cards, "transactionAmountCents")).isEqualTo(10_000L); assertThat(longValue(cards, "subsidyAmountCents")).isEqualTo(28_850L); assertThat(longValue(cards, "todayVerificationCount")).isEqualTo(2L); List> details = mapper.selectSettlementExportDetails(88L, 1, 1, start, end, 20); assertThat(details).hasSize(2); Map freeStay = details.stream() .filter(row -> "HOTEL_FREE".equals(String.valueOf(value(row, "orderType")))) .findFirst().orElseThrow(); assertThat(longValue(freeStay, "transactionAmountCents")).isZero(); assertThat(longValue(freeStay, "subsidyAmountCents")).isEqualTo(26_850L); assertThat(longValue(freeStay, "settlementAmountCents")).isEqualTo(26_850L); } } private void assertTotals(Map row) { assertThat(longValue(row, "orderCount")).isEqualTo(2L); assertThat(longValue(row, "transactionAmountCents")).isEqualTo(10_000L); assertThat(longValue(row, "subsidyAmountCents")).isEqualTo(28_850L); assertThat(longValue(row, "settlementAmountCents")).isEqualTo(38_850L); } private long longValue(Map row, String key) { Object value = value(row, key); return value instanceof Number number ? number.longValue() : 0L; } private Object value(Map row, String key) { for (Map.Entry entry : row.entrySet()) { if (entry.getKey().equalsIgnoreCase(key)) { return entry.getValue(); } } return null; } private void createSchema(DataSource dataSource) { JdbcTemplate jdbc = new JdbcTemplate(dataSource); jdbc.execute("create alias if not exists date_format for 'com.talentcard.server.mapper.MerchantSettlementStatisticsMapperTests.dateFormat'"); jdbc.execute(""" create table merchant ( id bigint primary key, merchant_name varchar(128), merchant_type varchar(64), merchant_type_code varchar(64), deleted tinyint not null default 0 ) """); jdbc.execute(""" create table benefit_order ( id bigint primary key, order_no varchar(64), order_type varchar(64), merchant_id bigint, store_id bigint, talent_id bigint, card_id bigint, benefit_id bigint, product_id bigint, coupon_id bigint, product_name_snapshot varchar(255), order_amount bigint, pay_amount bigint, coupon_amount bigint, subsidy_amount bigint, order_status tinyint, verify_status tinyint, created_at timestamp, updated_at timestamp, deleted tinyint not null default 0 ) """); jdbc.execute(""" create table verify_record ( id bigint primary key, verify_no varchar(64), order_id bigint, talent_id bigint, card_id bigint, merchant_id bigint, store_id bigint, staff_id bigint, verify_type varchar(64), verify_amount bigint, subsidy_amount bigint, verify_time timestamp, status tinyint not null default 1 ) """); jdbc.execute("create table merchant_product (id bigint primary key, product_name varchar(255), is_government_subsidy tinyint, deleted tinyint)"); jdbc.execute("create table merchant_coupon (id bigint primary key, government_subsidy tinyint, deleted tinyint)"); jdbc.execute("create table merchant_store (id bigint primary key, store_name varchar(128), deleted tinyint)"); jdbc.execute("create table talent_user (id bigint primary key, name varchar(64), mobile varchar(32), deleted tinyint)"); jdbc.execute("create table talent_card (id bigint primary key, card_no varchar(64), card_level varchar(64), deleted tinyint)"); } private void insertFixture(DataSource dataSource) { JdbcTemplate jdbc = new JdbcTemplate(dataSource); LocalDateTime now = LocalDateTime.now(); jdbc.update("insert into merchant(id, merchant_name, merchant_type, merchant_type_code, deleted) values (88, '测试酒店', '酒店服务', 'HOTEL', 0)"); jdbc.update("insert into merchant_store(id, store_name, deleted) values (7, '酒店门店', 0)"); jdbc.update("insert into talent_user(id, name, mobile, deleted) values (1015, '测试人才', '13800000000', 0)"); jdbc.update("insert into talent_card(id, card_no, card_level, deleted) values (10, 'TC001', '卓越人才卡', 0)"); jdbc.update(""" insert into benefit_order(id, order_no, order_type, merchant_id, store_id, talent_id, card_id, product_name_snapshot, order_amount, pay_amount, coupon_amount, subsidy_amount, order_status, verify_status, created_at, updated_at, deleted) values (1, 'O001', 'GROUP_BUY', 88, 7, 1015, 10, '测试团单', 12000, 10000, 0, 2000, 1, 1, ?, ?, 0) """, now, now); jdbc.update(""" insert into verify_record(id, verify_no, order_id, talent_id, card_id, merchant_id, store_id, staff_id, verify_type, verify_amount, subsidy_amount, verify_time, status) values (1, 'V001', 1, 1015, 10, 88, 7, 9, 'ORDER_CODE', 10000, 2000, ?, 1) """, now); jdbc.update(""" insert into verify_record(id, verify_no, order_id, talent_id, card_id, merchant_id, store_id, staff_id, verify_type, verify_amount, subsidy_amount, verify_time, status) values (2, 'V002', null, 1015, 10, 88, 7, 9, 'HOTEL_FREE', 0, 26850, ?, 1) """, now); } public static String dateFormat(java.sql.Timestamp value, String pattern) { DateTimeFormatter formatter = "%Y-%m".equals(pattern) ? DateTimeFormatter.ofPattern("yyyy-MM") : DateTimeFormatter.ofPattern("yyyy-MM-dd"); return value.toLocalDateTime().format(formatter); } }