|
|
@@ -24,9 +24,11 @@ import org.dromara.common.core.utils.StringUtils;
|
|
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
|
import org.dromara.common.redis.utils.SequenceUtils;
|
|
|
+import org.dromara.common.satoken.utils.LoginHelper;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
import java.util.*;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@@ -51,6 +53,10 @@ public class StatementInvoiceServiceImpl extends ServiceImpl<StatementInvoiceMap
|
|
|
|
|
|
private final StatementOrderMapper statementOrderMapper;
|
|
|
|
|
|
+ private final StatementDetailMapper statementDetailMapper;
|
|
|
+
|
|
|
+ private final StatementProductMapper statementProductMapper;
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* 查询销售发票主
|
|
|
@@ -187,33 +193,132 @@ public class StatementInvoiceServiceImpl extends ServiceImpl<StatementInvoiceMap
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * pc新增销售发票主
|
|
|
+ * PC端申请开票:支持同一客户的多个对账单合并申请
|
|
|
*
|
|
|
- * @param bo 销售发票主
|
|
|
- * @return 是否新增成功
|
|
|
+ * @param bo 开票申请参数(需包含 statementOrderIds)
|
|
|
+ * @return 创建成功的发票主单ID,或抛出异常
|
|
|
*/
|
|
|
@Override
|
|
|
- public Boolean pcInsertByBo(StatementInvoiceBo bo) {
|
|
|
- // 1. 设置发票编号
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public Long pcInsertByBo(StatementInvoiceBo bo) {
|
|
|
+ Set<Long> statementOrderIds = bo.getStatementOrderIds();
|
|
|
+ if (CollectionUtil.isEmpty(statementOrderIds)) {
|
|
|
+ throw new IllegalArgumentException("请选择要开票的对账单");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 批量查询所有对账单
|
|
|
+ List<StatementOrder> statementOrders = statementOrderMapper.selectBatchIds(statementOrderIds);
|
|
|
+ if (statementOrders.size() != statementOrderIds.size()) {
|
|
|
+ throw new RuntimeException("部分对账单不存在或已被删除");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 校验是否同一客户
|
|
|
+ String customerNo = statementOrders.get(0).getCustomerNo();
|
|
|
+ String customerName = statementOrders.get(0).getCustomerName();
|
|
|
+ boolean sameCustomer = statementOrders.stream()
|
|
|
+ .allMatch(so -> customerNo.equals(so.getCustomerNo()));
|
|
|
+ if (!sameCustomer) {
|
|
|
+ throw new RuntimeException("所选对账单不属于同一客户,无法合并开票");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 3. 计算总金额
|
|
|
+ BigDecimal totalAmount = statementOrders.stream()
|
|
|
+ .map(StatementOrder::getAmount)
|
|
|
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
+
|
|
|
+ // 4. 构建主单
|
|
|
+ bo.setCustomerName(customerName);
|
|
|
+ bo.setCustomerNo(customerNo);
|
|
|
+ bo.setInvoiceAmount(totalAmount);
|
|
|
+ bo.setInvoiceStatus(InvoiceStatus.NOT_INVOICED.getCode()); // 待确认
|
|
|
+
|
|
|
String statementInvoiceNo = SequenceUtils.generateOrderCode("BL");
|
|
|
bo.setStatementInvoiceNo(statementInvoiceNo);
|
|
|
|
|
|
- // 2. 设置初始状态为“待确认”
|
|
|
- bo.setInvoiceStatus(InvoiceStatus.NOT_INVOICED.getCode()); // 假设 PENDING = "0" 或 "pending"
|
|
|
-
|
|
|
- // 3. 转换并保存主表
|
|
|
StatementInvoice entity = MapstructUtils.convert(bo, StatementInvoice.class);
|
|
|
validEntityBeforeSave(entity);
|
|
|
- boolean success = this.save(entity);
|
|
|
+ boolean saved = this.save(entity);
|
|
|
+ if (!saved) {
|
|
|
+ throw new RuntimeException("保存开票申请主单失败");
|
|
|
+ }
|
|
|
|
|
|
- if (success) {
|
|
|
- bo.setId(entity.getId());
|
|
|
- // 4. 保存明细、商品、发票信息(不含真实发票)
|
|
|
- saveDetailsAndProductsAndInvoiceInfos(bo);
|
|
|
+ // 5. 批量查询所有明细和商品(按 statementOrderId + orderId)
|
|
|
+ List<StatementDetail> allDetails = statementDetailMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<StatementDetail>()
|
|
|
+ .in(StatementDetail::getStatementOrderId, statementOrderIds)
|
|
|
+ );
|
|
|
+
|
|
|
+ // 构建明细和商品列表
|
|
|
+ List<StatementInvoiceDetailBo> detailBoList = new ArrayList<>();
|
|
|
+ List<StatementInvoiceProductBo> productBoList = new ArrayList<>();
|
|
|
+
|
|
|
+ // 提取所有 (statementOrderId, orderId) 组合用于查商品
|
|
|
+ Set<String> orderKeys = allDetails.stream()
|
|
|
+ .map(d -> d.getStatementOrderId() + "_" + d.getOrderId())
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+
|
|
|
+ if (!orderKeys.isEmpty()) {
|
|
|
+ // 可考虑分页或分批,若数据量大
|
|
|
+ List<StatementProduct> allProducts = statementProductMapper.selectList(
|
|
|
+ new LambdaQueryWrapper<StatementProduct>()
|
|
|
+ .in(StatementProduct::getStatementOrderId, statementOrderIds)
|
|
|
+ );
|
|
|
+
|
|
|
+ // 建立 product 映射:(statementOrderId, orderId) -> List<product>
|
|
|
+ Map<String, List<StatementProduct>> productMap = allProducts.stream()
|
|
|
+ .collect(Collectors.groupingBy(p ->
|
|
|
+ p.getStatementOrderId() + "_" + p.getOrderId()
|
|
|
+ ));
|
|
|
+
|
|
|
+ // 构建明细和商品BO
|
|
|
+ for (StatementDetail detail : allDetails) {
|
|
|
+ StatementInvoiceDetailBo detailBo = new StatementInvoiceDetailBo();
|
|
|
+ detailBo.setStatementInvoiceId(entity.getId());
|
|
|
+ detailBo.setStatementInvoiceNo(entity.getStatementInvoiceNo());
|
|
|
+ detailBo.setStatementAmount(detail.getAmount());
|
|
|
+ detailBo.setOrderId(detail.getOrderId());
|
|
|
+ detailBo.setOrderNo(detail.getOrderNo());
|
|
|
+ detailBo.setOrderAmount(detail.getAmount());
|
|
|
+ detailBo.setOrderTime(detail.getOrderTime());
|
|
|
+ detailBo.setSigningDate(detail.getSigningDate());
|
|
|
+ detailBo.setUserId(LoginHelper.getUserId());
|
|
|
+ detailBo.setUserDeptId(LoginHelper.getDeptId());
|
|
|
+ detailBo.setStatementOrderId(detail.getStatementOrderId());
|
|
|
+ detailBo.setStatementOrderNo(detail.getStatementOrderNo());
|
|
|
+ detailBoList.add(detailBo);
|
|
|
+
|
|
|
+ // 添加对应商品
|
|
|
+ String key = detail.getStatementOrderId() + "_" + detail.getOrderId();
|
|
|
+ List<StatementProduct> products = productMap.get(key);
|
|
|
+ if (CollectionUtil.isNotEmpty(products)) {
|
|
|
+ for (StatementProduct p : products) {
|
|
|
+ StatementInvoiceProductBo productBo = new StatementInvoiceProductBo();
|
|
|
+ productBo.setStatementInvoiceId(entity.getId());
|
|
|
+ productBo.setStatementInvoiceNo(entity.getStatementInvoiceNo());
|
|
|
+ productBo.setProductId(p.getProductId());
|
|
|
+ productBo.setProductNo(p.getProductNo());
|
|
|
+ productBo.setOrderId(p.getOrderId());
|
|
|
+ productBo.setOrderNo(p.getOrderNo());
|
|
|
+ productBo.setItemName(p.getItemName());
|
|
|
+ productBo.setUnitId(p.getUnitId());
|
|
|
+ productBo.setUnitName(p.getUnitName());
|
|
|
+ productBo.setQuantity(p.getQuantity());
|
|
|
+ productBo.setUnitPrice(p.getUnitPrice());
|
|
|
+ productBoList.add(productBo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+ // 6. 设置子表并保存
|
|
|
+ bo.setId(entity.getId());
|
|
|
+ bo.setDetailList(detailBoList);
|
|
|
+ bo.setProductList(productBoList);
|
|
|
+ // bo.setInvoiceList(null); // 申请阶段通常无真实发票信息
|
|
|
|
|
|
- return success;
|
|
|
+ saveDetailsAndProductsAndInvoiceInfos(bo);
|
|
|
+
|
|
|
+ return entity.getId(); // 返回主单ID,便于前端跳转或提示
|
|
|
}
|
|
|
|
|
|
/**
|