fix: allow expired scanned talent codes for consumption
| | |
| | | Map<String, Object> coupon = usableCoupon(principal.merchantId(), number(source.get("talentId")), string(source.get("cardLevel")), request.couponId(), discountedAmount(rule, request.amount())); |
| | | Map<String, Object> amounts = quote(rule, coupon, request.amount()); |
| | | Long dynamicCodeId = number(source.get("dynamicCodeId")); |
| | | int codeUpdated = jdbc.update(""" |
| | | update talent_dynamic_code set status = 1, merchant_id = ?, used_at = now() |
| | | where id = ? and status = 0 |
| | | """, principal.merchantId(), dynamicCodeId); |
| | | int codeUpdated = consumeScannedTalentCode(principal, dynamicCodeId); |
| | | if (codeUpdated == 0) { |
| | | throw new BusinessException(ErrorCode.CONFLICT, "人才码已被使用或已失效"); |
| | | } |
| | |
| | | return sources.get(0); |
| | | } |
| | | |
| | | int consumeScannedTalentCode(MerchantPrincipal principal, Long dynamicCodeId) { |
| | | return jdbc.update(""" |
| | | update talent_dynamic_code set status = 1, merchant_id = ?, used_at = now() |
| | | where id = ? and status in (0, 2) |
| | | """, principal.merchantId(), dynamicCodeId); |
| | | } |
| | | |
| | | private void ensurePending(Map<String, Object> source) { |
| | | if (number(source.get("attemptStatus")) != ATTEMPT_PENDING) { |
| | | throw new BusinessException(ErrorCode.CONFLICT, "该人才码已处理,请重新扫码"); |
| New file |
| | |
| | | package com.talentcard.server.business.merchant; |
| | | |
| | | import static org.assertj.core.api.Assertions.assertThat; |
| | | |
| | | import com.talentcard.server.business.merchant.auth.MerchantPrincipal; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.jdbc.core.JdbcTemplate; |
| | | import org.springframework.jdbc.datasource.DriverManagerDataSource; |
| | | |
| | | class ManualConsumptionServiceTests { |
| | | |
| | | private JdbcTemplate jdbc; |
| | | private ManualConsumptionService service; |
| | | private MerchantPrincipal principal; |
| | | |
| | | @BeforeEach |
| | | void setUp() { |
| | | DriverManagerDataSource dataSource = new DriverManagerDataSource( |
| | | "jdbc:h2:mem:manual-consumption-" + System.nanoTime() + ";MODE=MySQL;DB_CLOSE_DELAY=-1", "sa", ""); |
| | | jdbc = new JdbcTemplate(dataSource); |
| | | jdbc.execute(""" |
| | | create table talent_dynamic_code ( |
| | | id bigint primary key, |
| | | status tinyint not null, |
| | | merchant_id bigint, |
| | | used_at timestamp |
| | | ) |
| | | """); |
| | | service = new ManualConsumptionService(jdbc); |
| | | principal = new MerchantPrincipal(9L, 88L, 7L, "operator"); |
| | | } |
| | | |
| | | @Test |
| | | void consumesActiveOrExpiredCodeAfterSuccessfulScan() { |
| | | jdbc.update("insert into talent_dynamic_code(id, status) values (1, 0), (2, 2)"); |
| | | |
| | | assertThat(service.consumeScannedTalentCode(principal, 1L)).isEqualTo(1); |
| | | assertThat(service.consumeScannedTalentCode(principal, 2L)).isEqualTo(1); |
| | | assertThat(jdbc.queryForObject("select status from talent_dynamic_code where id = 1", Integer.class)).isEqualTo(1); |
| | | assertThat(jdbc.queryForObject("select status from talent_dynamic_code where id = 2", Integer.class)).isEqualTo(1); |
| | | } |
| | | |
| | | @Test |
| | | void rejectsAlreadyUsedCode() { |
| | | jdbc.update("insert into talent_dynamic_code(id, status, merchant_id) values (3, 1, 66)"); |
| | | |
| | | assertThat(service.consumeScannedTalentCode(principal, 3L)).isZero(); |
| | | assertThat(jdbc.queryForObject("select merchant_id from talent_dynamic_code where id = 3", Long.class)).isEqualTo(66L); |
| | | } |
| | | } |