优化
This commit is contained in:
@@ -3,7 +3,20 @@ package com.baiyue.firstleg.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baiyue.firstleg.entity.InboundFeeDetailEntity;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
|
||||
@Mapper
|
||||
public interface InboundFeeDetailMapper extends BaseMapper<InboundFeeDetailEntity> {
|
||||
@Update("""
|
||||
UPDATE fl_inbound_fee_detail
|
||||
SET deleted = 1, updated_at = CURRENT_TIMESTAMP(3)
|
||||
WHERE tenant_id = #{tenantId}
|
||||
AND inbound_id = #{inboundId}
|
||||
AND id = #{detailId}
|
||||
AND deleted = 0
|
||||
""")
|
||||
int logicallyDelete(@Param("tenantId") long tenantId,
|
||||
@Param("inboundId") long inboundId,
|
||||
@Param("detailId") long detailId);
|
||||
}
|
||||
|
||||
@@ -165,10 +165,8 @@ public class FeeItemRepository {
|
||||
.eq(InboundFeeDetailEntity::getId, detail.getId()));
|
||||
}
|
||||
|
||||
public int deleteDetail(long tenantId, long detailId) {
|
||||
return feeDetails.delete(new LambdaQueryWrapper<InboundFeeDetailEntity>()
|
||||
.eq(InboundFeeDetailEntity::getTenantId, tenantId)
|
||||
.eq(InboundFeeDetailEntity::getId, detailId));
|
||||
public int deleteDetail(long tenantId, long inboundId, long detailId) {
|
||||
return feeDetails.logicallyDelete(tenantId, inboundId, detailId);
|
||||
}
|
||||
|
||||
public int review(long tenantId, long inboundId, long detailId, String targetStatus,
|
||||
|
||||
@@ -159,7 +159,9 @@ public class InboundFeeDetailService {
|
||||
@Transactional
|
||||
public void delete(long tenantId, long inboundId, long detailId) {
|
||||
requiredEditable(tenantId, inboundId, detailId);
|
||||
if (repository.deleteDetail(tenantId, detailId) != 1) throw conflict("费用明细删除冲突");
|
||||
if (repository.deleteDetail(tenantId, inboundId, detailId) != 1) {
|
||||
throw conflict("费用明细删除冲突");
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
||||
+16
@@ -8,6 +8,22 @@ import java.nio.charset.StandardCharsets;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class FinanceFeeSourceMigrationContractTest {
|
||||
@Test
|
||||
void freshSchemaAndMigrationExposeInboundFeePartnerSnapshotsUsedByAllFeeFlows() throws Exception {
|
||||
String baseline = new ClassPathResource("db/phase2-fee-item-and-inbound-detail.sql")
|
||||
.getContentAsString(StandardCharsets.UTF_8);
|
||||
String migration = new ClassPathResource("db/finance-fee-source-migration.sql")
|
||||
.getContentAsString(StandardCharsets.UTF_8);
|
||||
|
||||
assertThat(baseline).contains(
|
||||
"partner_id BIGINT UNSIGNED NULL",
|
||||
"partner_name VARCHAR(200) NULL");
|
||||
assertThat(migration).contains(
|
||||
"firstleg_finance_add_column('fl_inbound_fee_detail', 'partner_id'",
|
||||
"firstleg_finance_add_column('fl_inbound_fee_detail', 'partner_name'",
|
||||
"Firstleg Finance迁移失败:入库费用往来单位快照字段不完整");
|
||||
}
|
||||
|
||||
@Test
|
||||
void migrationDefinesIdempotentOutboxEnvelopeAndContainerFeeModel() throws Exception {
|
||||
String sql = new ClassPathResource("db/finance-fee-source-migration.sql")
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.baiyue.firstleg.repository;
|
||||
|
||||
import com.baiyue.firstleg.mapper.InboundFeeDetailMapper;
|
||||
import org.apache.ibatis.annotations.Update;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class InboundFeeDetailMapperContractTest {
|
||||
@Test
|
||||
void logicalDeleteIsScopedToCustomerInboundDetailAndActiveRow() throws Exception {
|
||||
Method method = InboundFeeDetailMapper.class.getMethod(
|
||||
"logicallyDelete", long.class, long.class, long.class);
|
||||
String sql = String.join(" ", method.getAnnotation(Update.class).value())
|
||||
.replaceAll("\\s+", " ").toLowerCase();
|
||||
|
||||
assertThat(sql)
|
||||
.contains("set deleted = 1")
|
||||
.contains("tenant_id = #{tenantid}")
|
||||
.contains("inbound_id = #{inboundid}")
|
||||
.contains("id = #{detailid}")
|
||||
.contains("deleted = 0");
|
||||
}
|
||||
}
|
||||
+3
-6
@@ -112,15 +112,12 @@ class TenantScopedMutationRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
void feeDetailDeleteMatchesTenantAndId() {
|
||||
when(feeDetails.delete(any(Wrapper.class))).thenReturn(1);
|
||||
when(feeDetails.logicallyDelete(TENANT, 77L, ID)).thenReturn(1);
|
||||
|
||||
assertThat(feeRepository.deleteDetail(TENANT, ID)).isEqualTo(1);
|
||||
assertThat(feeRepository.deleteDetail(TENANT, 77L, ID)).isEqualTo(1);
|
||||
|
||||
ArgumentCaptor<Wrapper<InboundFeeDetailEntity>> wrapper = ArgumentCaptor.forClass(Wrapper.class);
|
||||
verify(feeDetails).delete(wrapper.capture());
|
||||
assertTenantAndId(wrapper.getValue());
|
||||
verify(feeDetails).logicallyDelete(TENANT, 77L, ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -56,7 +56,20 @@ class FeeManagementServiceTest {
|
||||
.hasMessageContaining("费用明细不存在");
|
||||
|
||||
verify(repository).findDetail(10002L, 21L, 31L);
|
||||
verify(repository, never()).deleteDetail(10002L, 31L);
|
||||
verify(repository, never()).deleteDetail(10002L, 21L, 31L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("待审核费用明细按客户和入库单作用域删除")
|
||||
void deletesPendingFeeDetailInInboundScope() {
|
||||
InboundFeeDetailEntity pending = new InboundFeeDetailEntity();
|
||||
pending.setReviewStatus("PENDING");
|
||||
when(repository.findDetail(10001L, 21L, 31L)).thenReturn(pending);
|
||||
when(repository.deleteDetail(10001L, 21L, 31L)).thenReturn(1);
|
||||
|
||||
details.delete(10001L, 21L, 31L);
|
||||
|
||||
verify(repository).deleteDetail(10001L, 21L, 31L);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user