套装书下单直接出库单品
This commit is contained in:
@@ -38,6 +38,14 @@ public interface ShopProductService extends IService<ShopProduct> {
|
|||||||
PageUtils queryPageactivityprice(Map<String, Object> params);
|
PageUtils queryPageactivityprice(Map<String, Object> params);
|
||||||
|
|
||||||
|
|
||||||
void rollbackStock(BuyOrder buyOrder);
|
/**
|
||||||
|
* 回滚订单行 shop_product 库存与销量。
|
||||||
|
* @param skipShopProductIds 已由 inv 出库回滚加过 shop 的商品,跳过库存回加(仍回滚销量)
|
||||||
|
*/
|
||||||
|
void rollbackStock(BuyOrder buyOrder, java.util.Set<Integer> skipShopProductIds);
|
||||||
|
|
||||||
|
default void rollbackStock(BuyOrder buyOrder) {
|
||||||
|
rollbackStock(buyOrder, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1201,6 +1201,7 @@ public class BuyOrderServiceImpl extends ServiceImpl<BuyOrderDao, BuyOrder> impl
|
|||||||
return refundFee;
|
return refundFee;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void refundOrder(BuyOrder buyOrder, MyUserEntity user, int refundId){
|
public void refundOrder(BuyOrder buyOrder, MyUserEntity user, int refundId){
|
||||||
if(buyOrder.getCouponId()!=null && buyOrder.getCouponId()!=0){
|
if(buyOrder.getCouponId()!=null && buyOrder.getCouponId()!=0){
|
||||||
couponService.rollbackCoupon(buyOrder.getCouponId());
|
couponService.rollbackCoupon(buyOrder.getCouponId());
|
||||||
@@ -1229,10 +1230,10 @@ public class BuyOrderServiceImpl extends ServiceImpl<BuyOrderDao, BuyOrder> impl
|
|||||||
//撤回课程权限
|
//撤回课程权限
|
||||||
log.info("====remove========="+buyOrder.getOrderSn());
|
log.info("====remove========="+buyOrder.getOrderSn());
|
||||||
removeCourseToUser(buyOrder);
|
removeCourseToUser(buyOrder);
|
||||||
//回滚库存
|
// 先按出库流水回加 inv remain + 出库商品 shop;再回加订单行中未出现在出库流水的商品 shop(如套书本身)
|
||||||
shopProductService.rollbackStock(buyOrder);
|
java.util.Set<Integer> invRestoredShopIds =
|
||||||
// 回滚 inv 售出流水:回加采购 remain_quantity,售出记录 del_flag=1
|
inventoryManagementService.rollbackSaleByOrderId(buyOrder.getOrderId());
|
||||||
inventoryManagementService.rollbackSaleByOrderId(buyOrder.getOrderId());
|
shopProductService.rollbackStock(buyOrder, invRestoredShopIds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,14 +141,23 @@ public class ShopProductServiceImpl extends ServiceImpl<ShopProductDao, ShopProd
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void rollbackStock(BuyOrder buyOrder){
|
public void rollbackStock(BuyOrder buyOrder, java.util.Set<Integer> skipShopProductIds){
|
||||||
QueryWrapper<BuyOrderProduct> buyOrderProductQueryWrapper = new QueryWrapper<>();
|
QueryWrapper<BuyOrderProduct> buyOrderProductQueryWrapper = new QueryWrapper<>();
|
||||||
buyOrderProductQueryWrapper.eq("order_id", buyOrder.getOrderId());
|
buyOrderProductQueryWrapper.eq("order_id", buyOrder.getOrderId());
|
||||||
List<BuyOrderProduct> buyOrderProductList = buyOrderProductService.list(buyOrderProductQueryWrapper);
|
List<BuyOrderProduct> buyOrderProductList = buyOrderProductService.list(buyOrderProductQueryWrapper);
|
||||||
for (BuyOrderProduct buyOrderProduct : buyOrderProductList) {
|
for (BuyOrderProduct buyOrderProduct : buyOrderProductList) {
|
||||||
Integer productId = buyOrderProduct.getProductId();
|
Integer productId = buyOrderProduct.getProductId();
|
||||||
ShopProduct product = this.getById(productId);
|
ShopProduct product = this.getById(productId);
|
||||||
product.setProductStock(product.getProductStock() + buyOrderProduct.getQuantity());
|
if (product == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// inv 出库回滚已加过 shop 的商品不再重复加库存;销量仍回滚
|
||||||
|
if (skipShopProductIds == null || !skipShopProductIds.contains(productId)) {
|
||||||
|
int stock = product.getProductStock() == null ? 0 : product.getProductStock();
|
||||||
|
product.setProductStock(stock + buyOrderProduct.getQuantity());
|
||||||
|
}
|
||||||
|
int sales = product.getSumSales() == null ? 0 : product.getSumSales();
|
||||||
|
product.setSumSales(Math.max(0, sales - buyOrderProduct.getQuantity()));
|
||||||
this.updateById(product);
|
this.updateById(product);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,9 +46,10 @@ public class InventoryManagementController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 采购/售出;
|
* 采购/售出;
|
||||||
* 采购 source:ls灵枢 zm众秒 other其他 publisher出版社,默认 other;跨商户采购自动两步;
|
* 采购 source:ls灵枢 zm众秒 other其他 publisher出版社,默认 other;跨商户采购自动两步;套书不支持入库;
|
||||||
* 列表返回时 source 按 sys_dict_data(dict_label=inventory_source_type) 的 dict_type→dict_value 转换;
|
* 列表返回时 source 按 sys_dict_data(dict_label=inventory_source_type) 的 dict_type→dict_value 转换;
|
||||||
* 售出出库类型:outboundType 或 source,取自 sys_dict_data(dict_label=inventory_outbound_type) 的 dict_type
|
* 售出出库类型:outboundType 或 source,取自 sys_dict_data(dict_label=inventory_outbound_type) 的 dict_type;
|
||||||
|
* 套书售出拆成单本出库
|
||||||
*/
|
*/
|
||||||
@RequestMapping("/purchaseProduct")
|
@RequestMapping("/purchaseProduct")
|
||||||
public R purchaseProduct(@RequestBody InvStockRecordDto dto) {
|
public R purchaseProduct(@RequestBody InvStockRecordDto dto) {
|
||||||
|
|||||||
@@ -20,19 +20,21 @@ public interface InventoryManagementService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 图书订单售出:写入 inv_stock_record 售出流水。
|
* 图书订单售出:写入 inv_stock_record 售出流水。
|
||||||
* 天医币支付固定扣众秒库存(merchant_id=2);其它支付按商品 payMerchant。
|
* 天医币支付固定扣众秒(merchant_id=2);其它支付严格按商品 payMerchant(1→灵枢,0→众秒),不跨商户回退。
|
||||||
|
* 套书(shop_product_book 关联多本)拆成单本商品分别出库扣库存。
|
||||||
*/
|
*/
|
||||||
void saleByBookOrder(Integer productId, int quantity, BuyOrder buyOrder, ShopProduct product);
|
void saleByBookOrder(Integer productId, int quantity, BuyOrder buyOrder, ShopProduct product);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* inv_stock_record 中是否存在该商品记录。
|
* inv_stock_record 中是否存在该商品记录。
|
||||||
* 天医币支付只查众秒(merchant_id=2);其它支付查对应商户(无则任一商户有流水也算)。
|
* 天医币支付只查众秒(merchant_id=2);其它支付查对应商户(无则任一商户有流水也算)。
|
||||||
|
* 套书查套内单本商品流水。
|
||||||
*/
|
*/
|
||||||
boolean hasInvStockRecord(Integer productId, BuyOrder buyOrder, ShopProduct product);
|
boolean hasInvStockRecord(Integer productId, BuyOrder buyOrder, ShopProduct product);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验图书库存流水:无记录则通过;有记录则剩余库存须不少于购买数量。
|
* 校验图书库存流水:无记录则通过;有记录则目标商户剩余须不少于购买数量。
|
||||||
* 天医币支付固定校验众秒库存。
|
* 天医币支付固定校验众秒库存。套书校验套内每本单品库存。
|
||||||
*/
|
*/
|
||||||
boolean validateBookInvStock(Integer productId, int quantity, BuyOrder buyOrder, ShopProduct product);
|
boolean validateBookInvStock(Integer productId, int quantity, BuyOrder buyOrder, ShopProduct product);
|
||||||
|
|
||||||
@@ -43,12 +45,14 @@ public interface InventoryManagementService {
|
|||||||
List<Map<String, Object>> exportStockStatistics(Map<String, Object> params);
|
List<Map<String, Object>> exportStockStatistics(Map<String, Object> params);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按订单回滚库存流水售出:回加采购批次 remain_quantity,售出记录 del_flag=1
|
* 按订单回滚出库:根据 order_id 查出全部售出流水,回加采购 remain,
|
||||||
|
* 并按出库商品回加对应 shop_product;返回已回加 shop 的商品ID集合,供业务侧避免重复回加。
|
||||||
*/
|
*/
|
||||||
void rollbackSaleByOrderId(Integer orderId);
|
java.util.Set<Integer> rollbackSaleByOrderId(Integer orderId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Excel 批量售出:全部解析/匹配成功才入库,任一条失败则全部不入库
|
* Excel 批量售出:全部解析/匹配成功才入库,任一条失败则全部不入库。
|
||||||
|
* 套书行按 App 逻辑拆成单本出库。
|
||||||
*
|
*
|
||||||
* @param merchantId 商户ID
|
* @param merchantId 商户ID
|
||||||
* @param outboundType 出库类型 donation/taobao/app
|
* @param outboundType 出库类型 donation/taobao/app
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.peanut.modules.master.service.impl;
|
|||||||
|
|
||||||
import com.alipay.api.domain.Product;
|
import com.alipay.api.domain.Product;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
||||||
@@ -228,6 +229,13 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
}
|
}
|
||||||
if (dto.getBiz_type() == InvStockRecord.BIZ_TYPE_SALE) {
|
if (dto.getBiz_type() == InvStockRecord.BIZ_TYPE_SALE) {
|
||||||
String outboundType = resolveOutboundType(dto.getOutboundType());
|
String outboundType = resolveOutboundType(dto.getOutboundType());
|
||||||
|
ShopProduct saleProduct = shopProductDao.selectById(dto.getProductId());
|
||||||
|
if (isSetBookProduct(saleProduct)) {
|
||||||
|
// 套书拆单出库:成本取各单本 FIFO 批次,不用请求里的套书 unitCost
|
||||||
|
saleSetBook(dto.getMerchantId(), dto.getQuantity(), saleProduct, outboundType,
|
||||||
|
null, dto.getRemark(), null, null, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
List<CostSplit> splits = deductPurchaseStockFifo(dto.getProductId(), dto.getMerchantId(), dto.getQuantity());
|
List<CostSplit> splits = deductPurchaseStockFifo(dto.getProductId(), dto.getMerchantId(), dto.getQuantity());
|
||||||
for (CostSplit split : splits) {
|
for (CostSplit split : splits) {
|
||||||
BigDecimal saleUnitCost = (dto.getUnitCost() != null && dto.getUnitCost().compareTo(BigDecimal.ZERO) > 0)
|
BigDecimal saleUnitCost = (dto.getUnitCost() != null && dto.getUnitCost().compareTo(BigDecimal.ZERO) > 0)
|
||||||
@@ -244,6 +252,11 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
throw new RuntimeException("单位成本必须大于0");
|
throw new RuntimeException("单位成本必须大于0");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShopProduct product = shopProductDao.selectById(dto.getProductId());
|
||||||
|
if (isSetBookProduct(product)) {
|
||||||
|
throw new RuntimeException("套书不支持入库");
|
||||||
|
}
|
||||||
|
|
||||||
// 采购:跨商户调拨 = 来源方按成本批次多条出库 + 本商户一条采购(成本取接口传值)
|
// 采购:跨商户调拨 = 来源方按成本批次多条出库 + 本商户一条采购(成本取接口传值)
|
||||||
// 灵枢→众秒:灵枢出库 outbound_type=zm;众秒→灵枢:众秒出库 outbound_type=ls
|
// 灵枢→众秒:灵枢出库 outbound_type=zm;众秒→灵枢:众秒出库 outbound_type=ls
|
||||||
if (isCrossMerchantTransfer(dto.getMerchantId(), dto.getSource())) {
|
if (isCrossMerchantTransfer(dto.getMerchantId(), dto.getSource())) {
|
||||||
@@ -261,47 +274,11 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 普通采购(source=other 等)
|
// 普通采购(source=other 等)
|
||||||
ShopProduct product = shopProductDao.selectById(dto.getProductId());
|
|
||||||
if (isSetBookProduct(product)) {
|
|
||||||
purchaseSetBook(dto, product);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
insertRecord(dto.getProductId(), dto.getMerchantId(), normalizeSource(dto.getSource()),
|
insertRecord(dto.getProductId(), dto.getMerchantId(), normalizeSource(dto.getSource()),
|
||||||
InvStockRecord.BIZ_TYPE_PURCHASE, dto.getQuantity(), dto.getUnitCost(), dto.getRemark());
|
InvStockRecord.BIZ_TYPE_PURCHASE, dto.getQuantity(), dto.getUnitCost(), dto.getRemark());
|
||||||
adjustShopProductStock(dto.getProductId(), dto.getQuantity());
|
adjustShopProductStock(dto.getProductId(), dto.getQuantity());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 套装书采购:套书库存增加,套内每本单品按当前商户 FIFO 出库并扣减 shop_product 库存。
|
|
||||||
* 套内图书从 shop_product_book 按套书 product_id 关联查询。
|
|
||||||
*/
|
|
||||||
private void purchaseSetBook(InvStockRecordDto dto, ShopProduct setProduct) {
|
|
||||||
List<Integer> bookIds = listBookIdsByProductId(setProduct.getProductId());
|
|
||||||
if (bookIds.isEmpty()) {
|
|
||||||
throw new RuntimeException("套书未在shop_product_book中关联图书");
|
|
||||||
}
|
|
||||||
int merchantId = dto.getMerchantId();
|
|
||||||
int quantity = dto.getQuantity();
|
|
||||||
validateSetBookComponentStock(bookIds, merchantId, quantity, setProduct.getProductId());
|
|
||||||
|
|
||||||
String saleSource = merchantIdToSource(merchantId);
|
|
||||||
String outboundRemark = "套书采购出库[" + setProduct.getProductName() + ",productId=" + setProduct.getProductId() + "]";
|
|
||||||
Long setPurchaseRecordId = insertRecord(dto.getProductId(), merchantId, normalizeSource(dto.getSource()),
|
|
||||||
null, InvStockRecord.BIZ_TYPE_PURCHASE, quantity, dto.getUnitCost(), dto.getRemark(),
|
|
||||||
null, null, null, null, null);
|
|
||||||
for (Integer bookId : bookIds) {
|
|
||||||
ShopProduct component = findComponentProductByBookId(bookId, setProduct.getProductId());
|
|
||||||
List<CostSplit> splits = deductPurchaseStockFifo(component.getProductId(), merchantId, quantity);
|
|
||||||
for (CostSplit split : splits) {
|
|
||||||
insertRecord(component.getProductId(), merchantId, saleSource, InvStockRecord.OUTBOUND_BOOKS,
|
|
||||||
InvStockRecord.BIZ_TYPE_SALE, -split.quantity, split.unitCost, outboundRemark,
|
|
||||||
null, null, null, split.purchaseRecordId, setPurchaseRecordId);
|
|
||||||
}
|
|
||||||
adjustShopProductStock(component.getProductId(), -quantity);
|
|
||||||
}
|
|
||||||
adjustShopProductStock(dto.getProductId(), quantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 套书判定:shop_product_book 中关联图书数 > 1 */
|
/** 套书判定:shop_product_book 中关联图书数 > 1 */
|
||||||
private boolean isSetBookProduct(ShopProduct product) {
|
private boolean isSetBookProduct(ShopProduct product) {
|
||||||
if (product == null || product.getProductId() == null) {
|
if (product == null || product.getProductId() == null) {
|
||||||
@@ -346,7 +323,7 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
if (candidateId == null) {
|
if (candidateId == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 同一 book_id 可能关联套书与单品,优先取 shop_product_book 中仅关联 1 本书的单品 product_id
|
// 必须是 shop_product_book 中只绑定了 1 本书的单品 product_id
|
||||||
Long bookCount = shopProductBookDao.selectCount(
|
Long bookCount = shopProductBookDao.selectCount(
|
||||||
new LambdaQueryWrapper<ShopProductBookEntity>()
|
new LambdaQueryWrapper<ShopProductBookEntity>()
|
||||||
.eq(ShopProductBookEntity::getProductId, candidateId)
|
.eq(ShopProductBookEntity::getProductId, candidateId)
|
||||||
@@ -355,9 +332,6 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
componentProductId = candidateId;
|
componentProductId = candidateId;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (componentProductId == null) {
|
|
||||||
componentProductId = candidateId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (componentProductId == null) {
|
if (componentProductId == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -431,7 +405,13 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
if (quantity <= 0) {
|
if (quantity <= 0) {
|
||||||
throw new RuntimeException("售出数量必须大于0");
|
throw new RuntimeException("售出数量必须大于0");
|
||||||
}
|
}
|
||||||
int merchantId = resolveBookOrderMerchantId(productId, buyOrder, product, quantity);
|
int merchantId = resolveBookOrderMerchantId(buyOrder, product);
|
||||||
|
if (isSetBookProduct(product)) {
|
||||||
|
saleSetBook(merchantId, quantity, product, InvStockRecord.OUTBOUND_APP,
|
||||||
|
null, "套书订单售出[" + product.getProductName() + ",productId=" + productId + "]",
|
||||||
|
buyOrder, null, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
List<CostSplit> splits = deductPurchaseStockFifo(productId, merchantId, quantity);
|
List<CostSplit> splits = deductPurchaseStockFifo(productId, merchantId, quantity);
|
||||||
for (CostSplit split : splits) {
|
for (CostSplit split : splits) {
|
||||||
@@ -440,11 +420,45 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 套书出库:按 shop_product_book 拆成单本商品,分别 FIFO 扣库存并写售出流水。
|
||||||
|
* App 订单、手工出库、批量出库共用。
|
||||||
|
*/
|
||||||
|
private void saleSetBook(Integer merchantId, int quantity, ShopProduct setProduct, String outboundType,
|
||||||
|
BigDecimal overrideUnitCost, String remark, BuyOrder buyOrder,
|
||||||
|
Date createTime, String orderSn) {
|
||||||
|
Integer setProductId = setProduct.getProductId();
|
||||||
|
List<Integer> bookIds = listBookIdsByProductId(setProductId);
|
||||||
|
if (bookIds.isEmpty()) {
|
||||||
|
throw new RuntimeException("套书未在shop_product_book中关联图书");
|
||||||
|
}
|
||||||
|
validateSetBookComponentStock(bookIds, merchantId, quantity, setProductId);
|
||||||
|
String outboundRemark = (remark == null || remark.isBlank())
|
||||||
|
? "套书出库[" + setProduct.getProductName() + ",productId=" + setProductId + "]"
|
||||||
|
: remark;
|
||||||
|
for (Integer bookId : bookIds) {
|
||||||
|
ShopProduct component = findComponentProductByBookId(bookId, setProductId);
|
||||||
|
List<CostSplit> splits = deductPurchaseStockFifo(component.getProductId(), merchantId, quantity);
|
||||||
|
for (CostSplit split : splits) {
|
||||||
|
BigDecimal saleUnitCost = (overrideUnitCost != null && overrideUnitCost.compareTo(BigDecimal.ZERO) > 0)
|
||||||
|
? overrideUnitCost : split.unitCost;
|
||||||
|
insertSaleRecord(component.getProductId(), merchantId, outboundType,
|
||||||
|
-split.quantity, saleUnitCost, outboundRemark, buyOrder, createTime, orderSn,
|
||||||
|
split.purchaseRecordId);
|
||||||
|
}
|
||||||
|
adjustShopProductStock(component.getProductId(), -quantity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按订单回滚出库:出库记录有哪些商品,就回加哪些商品的 remain 与 shop_product。
|
||||||
|
* @return 已回加 shop 的商品ID,供取消/退款跳过订单行重复回加
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void rollbackSaleByOrderId(Integer orderId) {
|
public Set<Integer> rollbackSaleByOrderId(Integer orderId) {
|
||||||
if (orderId == null) {
|
if (orderId == null) {
|
||||||
return;
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
List<InvStockRecord> saleRecords = invStockRecordDao.selectList(
|
List<InvStockRecord> saleRecords = invStockRecordDao.selectList(
|
||||||
new LambdaQueryWrapper<InvStockRecord>()
|
new LambdaQueryWrapper<InvStockRecord>()
|
||||||
@@ -453,43 +467,69 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
.orderByDesc(InvStockRecord::getId)
|
.orderByDesc(InvStockRecord::getId)
|
||||||
);
|
);
|
||||||
if (saleRecords == null || saleRecords.isEmpty()) {
|
if (saleRecords == null || saleRecords.isEmpty()) {
|
||||||
return;
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
Map<Integer, Integer> shopRestoreMap = new LinkedHashMap<>();
|
||||||
|
// 先全部回加 remain,失败则整单回滚,避免只软删出库流水、库存没加回
|
||||||
for (InvStockRecord sale : saleRecords) {
|
for (InvStockRecord sale : saleRecords) {
|
||||||
int restoreQty = sale.getQuantity() == null ? 0 : Math.abs(sale.getQuantity());
|
int restoreQty = sale.getQuantity() == null ? 0 : Math.abs(sale.getQuantity());
|
||||||
if (restoreQty > 0) {
|
if (restoreQty <= 0) {
|
||||||
if (sale.getPurchaseRecordId() != null) {
|
continue;
|
||||||
restorePurchaseRemainById(sale.getPurchaseRecordId(), restoreQty);
|
|
||||||
} else {
|
|
||||||
restorePurchaseRemain(sale.getProductId(), sale.getMerchantId(), sale.getUnitCost(), restoreQty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// @TableLogic:deleteById 将 del_flag 置为 1
|
if (sale.getPurchaseRecordId() != null) {
|
||||||
|
restorePurchaseRemainById(sale.getPurchaseRecordId(), restoreQty);
|
||||||
|
} else {
|
||||||
|
restorePurchaseRemain(sale.getProductId(), sale.getMerchantId(), sale.getUnitCost(), restoreQty);
|
||||||
|
}
|
||||||
|
Integer saleProductId = sale.getProductId();
|
||||||
|
if (saleProductId != null) {
|
||||||
|
shopRestoreMap.merge(saleProductId, restoreQty, Integer::sum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (InvStockRecord sale : saleRecords) {
|
||||||
invStockRecordDao.deleteById(sale.getId());
|
invStockRecordDao.deleteById(sale.getId());
|
||||||
}
|
}
|
||||||
|
for (Map.Entry<Integer, Integer> entry : shopRestoreMap.entrySet()) {
|
||||||
|
adjustShopProductStock(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
return shopRestoreMap.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 按采购流水ID精确回加 remain_quantity(不超过该批次原始 quantity) */
|
/** 按采购流水ID原子回加 remain_quantity;失败抛错,禁止静默跳过 */
|
||||||
private void restorePurchaseRemainById(Long purchaseRecordId, int restoreQty) {
|
private void restorePurchaseRemainById(Long purchaseRecordId, int restoreQty) {
|
||||||
if (purchaseRecordId == null || restoreQty <= 0) {
|
if (purchaseRecordId == null || restoreQty <= 0) {
|
||||||
|
throw new RuntimeException("回滚库存参数无效,purchaseRecordId=" + purchaseRecordId + ", qty=" + restoreQty);
|
||||||
|
}
|
||||||
|
// 原子加回,避免 select+updateById 静默不生效
|
||||||
|
Integer rows = invStockRecordDao.update(null,
|
||||||
|
new LambdaUpdateWrapper<InvStockRecord>()
|
||||||
|
.eq(InvStockRecord::getId, purchaseRecordId)
|
||||||
|
.eq(InvStockRecord::getBizType, InvStockRecord.BIZ_TYPE_PURCHASE)
|
||||||
|
.apply("IFNULL(remain_quantity,0) + {0} <= IFNULL(quantity,0)", restoreQty)
|
||||||
|
.setSql("remain_quantity = IFNULL(remain_quantity,0) + " + restoreQty));
|
||||||
|
if (rows != null && rows > 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InvStockRecord purchase = invStockRecordDao.selectById(purchaseRecordId);
|
InvStockRecord purchase = invStockRecordDao.selectById(purchaseRecordId);
|
||||||
if (purchase == null || purchase.getBizType() == null
|
if (purchase == null || purchase.getBizType() == null
|
||||||
|| purchase.getBizType() != InvStockRecord.BIZ_TYPE_PURCHASE) {
|
|| !Integer.valueOf(InvStockRecord.BIZ_TYPE_PURCHASE).equals(purchase.getBizType())) {
|
||||||
return;
|
throw new RuntimeException("回滚库存失败,采购流水不存在或类型错误,purchaseRecordId=" + purchaseRecordId);
|
||||||
}
|
}
|
||||||
int originQty = purchase.getQuantity() == null ? 0 : purchase.getQuantity();
|
int originQty = purchase.getQuantity() == null ? 0 : purchase.getQuantity();
|
||||||
int remainQty = purchase.getRemainQuantity() == null ? 0 : purchase.getRemainQuantity();
|
int remainQty = purchase.getRemainQuantity() == null ? 0 : purchase.getRemainQuantity();
|
||||||
int capacity = Math.max(0, originQty - remainQty);
|
int capacity = Math.max(0, originQty - remainQty);
|
||||||
int add = Math.min(capacity, restoreQty);
|
int add = Math.min(capacity, restoreQty);
|
||||||
if (add <= 0) {
|
if (add > 0) {
|
||||||
return;
|
Integer updated = invStockRecordDao.update(null,
|
||||||
|
new LambdaUpdateWrapper<InvStockRecord>()
|
||||||
|
.eq(InvStockRecord::getId, purchaseRecordId)
|
||||||
|
.eq(InvStockRecord::getBizType, InvStockRecord.BIZ_TYPE_PURCHASE)
|
||||||
|
.setSql("remain_quantity = IFNULL(remain_quantity,0) + " + add));
|
||||||
|
if (updated == null || updated <= 0) {
|
||||||
|
throw new RuntimeException("回滚库存失败,更新采购剩余未生效,purchaseRecordId=" + purchaseRecordId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
purchase.setRemainQuantity(remainQty + add);
|
|
||||||
invStockRecordDao.updateById(purchase);
|
|
||||||
if (add < restoreQty) {
|
if (add < restoreQty) {
|
||||||
// 容量不够时按旧逻辑兜底补足(兼容脏数据)
|
|
||||||
restorePurchaseRemain(purchase.getProductId(), purchase.getMerchantId(),
|
restorePurchaseRemain(purchase.getProductId(), purchase.getMerchantId(),
|
||||||
purchase.getUnitCost(), restoreQty - add);
|
purchase.getUnitCost(), restoreQty - add);
|
||||||
}
|
}
|
||||||
@@ -499,9 +539,12 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
* 按成本单价逆 FIFO 回加采购批次剩余库存(不超过该批次原始 quantity)
|
* 按成本单价逆 FIFO 回加采购批次剩余库存(不超过该批次原始 quantity)
|
||||||
*/
|
*/
|
||||||
private void restorePurchaseRemain(Integer productId, Integer merchantId, BigDecimal unitCost, int restoreQty) {
|
private void restorePurchaseRemain(Integer productId, Integer merchantId, BigDecimal unitCost, int restoreQty) {
|
||||||
if (productId == null || merchantId == null || restoreQty <= 0) {
|
if (restoreQty <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (productId == null || merchantId == null) {
|
||||||
|
throw new RuntimeException("回滚库存失败,缺少商品或商户,productId=" + productId + ", merchantId=" + merchantId);
|
||||||
|
}
|
||||||
LambdaQueryWrapper<InvStockRecord> wrapper = new LambdaQueryWrapper<InvStockRecord>()
|
LambdaQueryWrapper<InvStockRecord> wrapper = new LambdaQueryWrapper<InvStockRecord>()
|
||||||
.eq(InvStockRecord::getProductId, productId)
|
.eq(InvStockRecord::getProductId, productId)
|
||||||
.eq(InvStockRecord::getMerchantId, merchantId)
|
.eq(InvStockRecord::getMerchantId, merchantId)
|
||||||
@@ -523,8 +566,15 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int add = Math.min(capacity, remaining);
|
int add = Math.min(capacity, remaining);
|
||||||
purchase.setRemainQuantity(remainQty + add);
|
Integer updated = invStockRecordDao.update(null,
|
||||||
invStockRecordDao.updateById(purchase);
|
new LambdaUpdateWrapper<InvStockRecord>()
|
||||||
|
.eq(InvStockRecord::getId, purchase.getId())
|
||||||
|
.eq(InvStockRecord::getBizType, InvStockRecord.BIZ_TYPE_PURCHASE)
|
||||||
|
.apply("IFNULL(remain_quantity,0) + {0} <= IFNULL(quantity,0)", add)
|
||||||
|
.setSql("remain_quantity = IFNULL(remain_quantity,0) + " + add));
|
||||||
|
if (updated == null || updated <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
remaining -= add;
|
remaining -= add;
|
||||||
}
|
}
|
||||||
if (remaining > 0 && unitCost != null) {
|
if (remaining > 0 && unitCost != null) {
|
||||||
@@ -541,6 +591,9 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
if (productId == null) {
|
if (productId == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (isSetBookProduct(product)) {
|
||||||
|
return hasSetBookComponentInvRecord(productId, buyOrder);
|
||||||
|
}
|
||||||
if (isPeanutCoinPay(buyOrder)) {
|
if (isPeanutCoinPay(buyOrder)) {
|
||||||
return hasInvOnMerchant(productId, InvStockRecord.MERCHANT_ZM);
|
return hasInvOnMerchant(productId, InvStockRecord.MERCHANT_ZM);
|
||||||
}
|
}
|
||||||
@@ -551,12 +604,50 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
return count != null && count > 0;
|
return count != null && count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 套书:任一单本组件有流水即进入 inv 校验(天医币只认众秒) */
|
||||||
|
private boolean hasSetBookComponentInvRecord(Integer setProductId, BuyOrder buyOrder) {
|
||||||
|
List<Integer> bookIds = listBookIdsByProductId(setProductId);
|
||||||
|
if (bookIds.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
boolean peanut = isPeanutCoinPay(buyOrder);
|
||||||
|
for (Integer bookId : bookIds) {
|
||||||
|
ShopProduct component = findComponentProductByBookId(bookId, setProductId);
|
||||||
|
if (component == null || component.getProductId() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (peanut) {
|
||||||
|
if (hasInvOnMerchant(component.getProductId(), InvStockRecord.MERCHANT_ZM)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Long count = invStockRecordDao.selectCount(
|
||||||
|
new LambdaQueryWrapper<InvStockRecord>()
|
||||||
|
.eq(InvStockRecord::getProductId, component.getProductId())
|
||||||
|
);
|
||||||
|
if (count != null && count > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean validateBookInvStock(Integer productId, int quantity, BuyOrder buyOrder, ShopProduct product) {
|
public boolean validateBookInvStock(Integer productId, int quantity, BuyOrder buyOrder, ShopProduct product) {
|
||||||
if (!hasInvStockRecord(productId, buyOrder, product)) {
|
if (!hasInvStockRecord(productId, buyOrder, product)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
int merchantId = resolveBookOrderMerchantId(productId, buyOrder, product, quantity);
|
int merchantId = resolveBookOrderMerchantId(buyOrder, product);
|
||||||
|
if (isSetBookProduct(product)) {
|
||||||
|
List<Integer> bookIds = listBookIdsByProductId(productId);
|
||||||
|
try {
|
||||||
|
validateSetBookComponentStock(bookIds, merchantId, quantity, productId);
|
||||||
|
return true;
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
int remain = sumRemainStockByMerchant(productId, merchantId);
|
int remain = sumRemainStockByMerchant(productId, merchantId);
|
||||||
return remain > 0 && remain >= quantity;
|
return remain > 0 && remain >= quantity;
|
||||||
}
|
}
|
||||||
@@ -566,35 +657,16 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
return buyOrder != null && Constants.PAYMENT_METHOD_VIRTUAL.equals(buyOrder.getPaymentMethod());
|
return buyOrder != null && Constants.PAYMENT_METHOD_VIRTUAL.equals(buyOrder.getPaymentMethod());
|
||||||
}
|
}
|
||||||
|
|
||||||
private int resolveBookOrderMerchantId(Integer productId, BuyOrder buyOrder, ShopProduct product, int needQty) {
|
/**
|
||||||
|
* 天医币固定众秒;其它支付严格按 payMerchant 映射,不因目标商户剩余为 0 而改扣另一商户。
|
||||||
|
* payMerchant=1 → 灵枢;否则 → 众秒。
|
||||||
|
*/
|
||||||
|
private int resolveBookOrderMerchantId(BuyOrder buyOrder, ShopProduct product) {
|
||||||
if (isPeanutCoinPay(buyOrder)) {
|
if (isPeanutCoinPay(buyOrder)) {
|
||||||
return InvStockRecord.MERCHANT_ZM;
|
return InvStockRecord.MERCHANT_ZM;
|
||||||
}
|
}
|
||||||
int payMerchant = product == null || product.getPayMerchant() == null ? 0 : product.getPayMerchant();
|
int payMerchant = product == null || product.getPayMerchant() == null ? 0 : product.getPayMerchant();
|
||||||
return resolveInvMerchantId(productId, payMerchant, needQty);
|
return payMerchant == 1 ? InvStockRecord.MERCHANT_LS : InvStockRecord.MERCHANT_ZM;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 优先按 payMerchant 对应商户扣库存;该商户剩余不足时,回退到另一商户(兼容入库商户与 pay_merchant 不一致)。
|
|
||||||
*/
|
|
||||||
private int resolveInvMerchantId(Integer productId, int payMerchant, int needQty) {
|
|
||||||
int preferred = payMerchant == 1 ? InvStockRecord.MERCHANT_LS : InvStockRecord.MERCHANT_ZM;
|
|
||||||
int other = preferred == InvStockRecord.MERCHANT_LS ? InvStockRecord.MERCHANT_ZM : InvStockRecord.MERCHANT_LS;
|
|
||||||
int preferredRemain = sumRemainStockByMerchant(productId, preferred);
|
|
||||||
if (preferredRemain >= needQty) {
|
|
||||||
return preferred;
|
|
||||||
}
|
|
||||||
int otherRemain = sumRemainStockByMerchant(productId, other);
|
|
||||||
if (otherRemain >= needQty) {
|
|
||||||
return other;
|
|
||||||
}
|
|
||||||
if (preferredRemain > 0 || hasInvOnMerchant(productId, preferred)) {
|
|
||||||
return preferred;
|
|
||||||
}
|
|
||||||
if (otherRemain > 0 || hasInvOnMerchant(productId, other)) {
|
|
||||||
return other;
|
|
||||||
}
|
|
||||||
return preferred;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasInvOnMerchant(Integer productId, int merchantId) {
|
private boolean hasInvOnMerchant(Integer productId, int merchantId) {
|
||||||
@@ -874,11 +946,39 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
Map<Integer, Integer> needQtyMap = new LinkedHashMap<>();
|
Map<Integer, Integer> needQtyMap = new LinkedHashMap<>();
|
||||||
Map<Integer, String> productNameMap = new HashMap<>();
|
Map<Integer, String> productNameMap = new HashMap<>();
|
||||||
for (BatchSaleRow row : rows) {
|
for (BatchSaleRow row : rows) {
|
||||||
needQtyMap.merge(row.productId, row.quantity, Integer::sum);
|
ShopProduct matched = shopProductDao.selectById(row.productId);
|
||||||
if (row.matchedName != null && !row.matchedName.isBlank()) {
|
if (isSetBookProduct(matched)) {
|
||||||
productNameMap.putIfAbsent(row.productId, row.matchedName);
|
List<Integer> bookIds = listBookIdsByProductId(row.productId);
|
||||||
|
if (bookIds.isEmpty()) {
|
||||||
|
errors.add("第" + row.excelRowNum + "行:套书未在shop_product_book中关联图书,productId=" + row.productId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (Integer bookId : bookIds) {
|
||||||
|
ShopProduct component = findComponentProductByBookId(bookId, row.productId);
|
||||||
|
if (component == null || component.getProductId() == null) {
|
||||||
|
String bookName = resolveBookName(bookId);
|
||||||
|
String bookPart = bookName.isBlank()
|
||||||
|
? "书籍ID[" + bookId + "]"
|
||||||
|
: "《" + bookName + "》(书籍ID:" + bookId + ")";
|
||||||
|
errors.add("第" + row.excelRowNum + "行:套书拆分失败," + bookPart + "无只绑1本的单品商品");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
needQtyMap.merge(component.getProductId(), row.quantity, Integer::sum);
|
||||||
|
String cName = component.getProductName();
|
||||||
|
if (cName != null && !cName.isBlank()) {
|
||||||
|
productNameMap.putIfAbsent(component.getProductId(), cName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
needQtyMap.merge(row.productId, row.quantity, Integer::sum);
|
||||||
|
if (row.matchedName != null && !row.matchedName.isBlank()) {
|
||||||
|
productNameMap.putIfAbsent(row.productId, row.matchedName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!errors.isEmpty()) {
|
||||||
|
throw new RuntimeException("全部未入库:" + String.join(";", errors));
|
||||||
|
}
|
||||||
for (Map.Entry<Integer, Integer> entry : needQtyMap.entrySet()) {
|
for (Map.Entry<Integer, Integer> entry : needQtyMap.entrySet()) {
|
||||||
int remain = sumRemainStockByMerchant(entry.getKey(), merchantId);
|
int remain = sumRemainStockByMerchant(entry.getKey(), merchantId);
|
||||||
if (remain < entry.getValue()) {
|
if (remain < entry.getValue()) {
|
||||||
@@ -892,8 +992,14 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (BatchSaleRow row : rows) {
|
for (BatchSaleRow row : rows) {
|
||||||
List<CostSplit> splits = deductPurchaseStockFifo(row.productId, merchantId, row.quantity);
|
ShopProduct matched = shopProductDao.selectById(row.productId);
|
||||||
String remark = "批量导入售出 orderSn=" + row.orderSn;
|
String remark = "批量导入售出 orderSn=" + row.orderSn;
|
||||||
|
if (isSetBookProduct(matched)) {
|
||||||
|
saleSetBook(merchantId, row.quantity, matched, normalizedOutbound,
|
||||||
|
null, remark, null, row.createTime, row.orderSn);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<CostSplit> splits = deductPurchaseStockFifo(row.productId, merchantId, row.quantity);
|
||||||
for (CostSplit split : splits) {
|
for (CostSplit split : splits) {
|
||||||
insertSaleRecord(row.productId, merchantId, normalizedOutbound,
|
insertSaleRecord(row.productId, merchantId, normalizedOutbound,
|
||||||
-split.quantity, split.unitCost, remark, null, row.createTime, row.orderSn, split.purchaseRecordId);
|
-split.quantity, split.unitCost, remark, null, row.createTime, row.orderSn, split.purchaseRecordId);
|
||||||
@@ -1254,7 +1360,7 @@ public class InventoryManagementServiceImpl extends ServiceImpl<InvStockRecordDa
|
|||||||
if (component == null || component.getProductId() == null) {
|
if (component == null || component.getProductId() == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// findComponentProductByBookId 已优先只绑 1 本书;再兜底确认
|
// findComponentProductByBookId 已要求只绑 1 本书;再兜底确认
|
||||||
if (listBookIdsByProductId(component.getProductId()).size() != 1) {
|
if (listBookIdsByProductId(component.getProductId()).size() != 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,23 +74,27 @@ public class OrderCancelConsumer {
|
|||||||
couponService.rollbackCoupon(couponHistoryId);
|
couponService.rollbackCoupon(couponHistoryId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 回滚商品库存与销量
|
// 先按出库流水回加 inv remain + 出库商品 shop_product
|
||||||
|
java.util.Set<Integer> invRestoredShopIds =
|
||||||
|
inventoryManagementService.rollbackSaleByOrderId(buyOrder.getOrderId());
|
||||||
|
|
||||||
|
// 回滚订单行 shop:出库流水已回加过的商品只回销量,不再加库存(单本避免双加;套书订单行仍会加回套书库存)
|
||||||
LambdaQueryWrapper<BuyOrderProduct> wrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<BuyOrderProduct> wrapper = new LambdaQueryWrapper<>();
|
||||||
wrapper.eq(BuyOrderProduct::getOrderId, buyOrder.getOrderId());
|
wrapper.eq(BuyOrderProduct::getOrderId, buyOrder.getOrderId());
|
||||||
List<BuyOrderProduct> buyOrderProducts = buyOrderProductDao.selectList(wrapper);
|
List<BuyOrderProduct> buyOrderProducts = buyOrderProductDao.selectList(wrapper);
|
||||||
for (BuyOrderProduct b : buyOrderProducts) {
|
for (BuyOrderProduct b : buyOrderProducts) {
|
||||||
ShopProduct shopProduct = shopProductDao.selectById(b.getProductId());
|
ShopProduct shopProduct = shopProductDao.selectById(b.getProductId());
|
||||||
if (shopProduct != null) {
|
if (shopProduct != null) {
|
||||||
int stock = shopProduct.getProductStock() == null ? 0 : shopProduct.getProductStock();
|
|
||||||
int sales = shopProduct.getSumSales() == null ? 0 : shopProduct.getSumSales();
|
int sales = shopProduct.getSumSales() == null ? 0 : shopProduct.getSumSales();
|
||||||
int qty = b.getQuantity();
|
int qty = b.getQuantity();
|
||||||
shopProduct.setProductStock(stock + qty);
|
if (invRestoredShopIds == null || !invRestoredShopIds.contains(b.getProductId())) {
|
||||||
|
int stock = shopProduct.getProductStock() == null ? 0 : shopProduct.getProductStock();
|
||||||
|
shopProduct.setProductStock(stock + qty);
|
||||||
|
}
|
||||||
shopProduct.setSumSales(Math.max(0, sales - qty));
|
shopProduct.setSumSales(Math.max(0, sales - qty));
|
||||||
shopProductDao.updateById(shopProduct);
|
shopProductDao.updateById(shopProduct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 回滚 inv 售出流水:回加采购 remain_quantity,售出记录 del_flag=1
|
|
||||||
inventoryManagementService.rollbackSaleByOrderId(buyOrder.getOrderId());
|
|
||||||
|
|
||||||
buyOrderService.updateById(buyOrder);
|
buyOrderService.updateById(buyOrder);
|
||||||
//buyOrderService.removeById(buyOrder);
|
//buyOrderService.removeById(buyOrder);
|
||||||
|
|||||||
Reference in New Issue
Block a user