|
|
@@ -931,29 +931,42 @@ class ProductClass extends BaseClass
|
|
|
|
|
|
/**
|
|
|
* 库存变动统一入口:用数据库行锁串行化同一花材的读-算-写,避免并发覆盖库存。
|
|
|
+ * 出现并发时,会自动重试3次。
|
|
|
+ * @param $productId
|
|
|
+ * @param callable $callback
|
|
|
+ * @return mixed
|
|
|
+ * @throws \Exception
|
|
|
*/
|
|
|
private static function runStockMutation($productId, callable $callback)
|
|
|
{
|
|
|
$db = Yii::$app->db;
|
|
|
$currentTransaction = $db->getTransaction();
|
|
|
$ownTransaction = empty($currentTransaction) || !$currentTransaction->isActive;
|
|
|
- $transaction = $ownTransaction ? $db->beginTransaction() : $currentTransaction;
|
|
|
- try {
|
|
|
- $productData = self::getLockById($productId);
|
|
|
- if (!$productData) {
|
|
|
- util::fail("花材不存在");
|
|
|
- }
|
|
|
- $respond = call_user_func($callback, $productData);
|
|
|
- if ($ownTransaction) {
|
|
|
- $transaction->commit();
|
|
|
- }
|
|
|
- return $respond;
|
|
|
- } catch (\Exception $exception) {
|
|
|
- if ($ownTransaction && !empty($transaction) && $transaction->isActive) {
|
|
|
- $transaction->rollBack();
|
|
|
+ $mutation = function () use ($db, $currentTransaction, $ownTransaction, $productId, $callback) {
|
|
|
+ $transaction = $ownTransaction ? $db->beginTransaction() : $currentTransaction;
|
|
|
+ try {
|
|
|
+ $productData = self::getLockById($productId);
|
|
|
+ if (!$productData) {
|
|
|
+ util::fail("花材不存在");
|
|
|
+ }
|
|
|
+ $respond = call_user_func($callback, $productData);
|
|
|
+ if ($ownTransaction) {
|
|
|
+ $transaction->commit();
|
|
|
+ }
|
|
|
+ return $respond;
|
|
|
+ } catch (\Exception $exception) {
|
|
|
+ if ($ownTransaction && !empty($transaction) && $transaction->isActive) {
|
|
|
+ $transaction->rollBack();
|
|
|
+ }
|
|
|
+ throw $exception;
|
|
|
}
|
|
|
- throw $exception;
|
|
|
+ };
|
|
|
+
|
|
|
+ if (!$ownTransaction) {
|
|
|
+ return call_user_func($mutation);
|
|
|
}
|
|
|
+
|
|
|
+ return util::runWithDbConcurrencyRetry($mutation);
|
|
|
}
|
|
|
|
|
|
//加库存,允许负库存,负数数量(盘点时)
|
|
|
@@ -961,7 +974,7 @@ class ProductClass extends BaseClass
|
|
|
{
|
|
|
//小单位库存不再考虑 ssh 20230303
|
|
|
//$itemNumPiece = 0;
|
|
|
- return self::runStockMutation($productId, function ($productData) use ($itemNumBundle, $itemNumPiece) {
|
|
|
+ $callback = function ($productData) use ($itemNumBundle, $itemNumPiece) {
|
|
|
$oldStock = $productData->stock;
|
|
|
$ratio = $productData->ratio;
|
|
|
//转成小数,加库存
|
|
|
@@ -975,7 +988,9 @@ class ProductClass extends BaseClass
|
|
|
$productData->save();
|
|
|
|
|
|
return ['oldStock' => $oldStock, 'newStock' => $newStock, 'itemNum' => $itemNum];
|
|
|
- });
|
|
|
+ };
|
|
|
+
|
|
|
+ return self::runStockMutation($productId, $callback);
|
|
|
}
|
|
|
|
|
|
//加路上库存
|
|
|
@@ -1002,7 +1017,7 @@ class ProductClass extends BaseClass
|
|
|
//加库存
|
|
|
public static function addStockByItemNum($productId, $itemNum, $params = [])
|
|
|
{
|
|
|
- return self::runStockMutation($productId, function ($productData) use ($itemNum, $params) {
|
|
|
+ $callback = function ($productData) use ($itemNum, $params) {
|
|
|
$oldStock = $productData->stock;
|
|
|
$newItemCost = 0;
|
|
|
$newItemStock = 0;
|
|
|
@@ -1050,7 +1065,9 @@ class ProductClass extends BaseClass
|
|
|
|
|
|
return ['oldStock' => $oldStock, 'newStock' => $newStock, 'itemNum' => $itemNum,
|
|
|
'avCost' => $avCost, 'totalCost' => $newItemCost, 'totalStock' => $newItemStock, 'changeCost' => $changeCost, 'unitCost' => $unitCost];
|
|
|
- });
|
|
|
+ };
|
|
|
+
|
|
|
+ return self::runStockMutation($productId, $callback);
|
|
|
}
|
|
|
|
|
|
//减库存,允许负库存,负数数量(盘点时)
|
|
|
@@ -1060,7 +1077,7 @@ class ProductClass extends BaseClass
|
|
|
{
|
|
|
//小单位库存不再考虑 ssh 20230303
|
|
|
//$itemNumPiece = 0;
|
|
|
- return self::runStockMutation($productId, function ($productData) use ($itemNumBundle, $itemNumPiece, $checkStock, $addSold, $params) {
|
|
|
+ $callback = function ($productData) use ($productId, $itemNumBundle, $itemNumPiece, $checkStock, $addSold, $params) {
|
|
|
$oldStock = $productData->stock;
|
|
|
$ratio = $productData->ratio;
|
|
|
//转成小数,更新库存
|
|
|
@@ -1130,14 +1147,16 @@ class ProductClass extends BaseClass
|
|
|
|
|
|
return ['oldStock' => $oldStock, 'newStock' => $newStock, 'itemNum' => $itemNum,
|
|
|
'avCost' => $avCost, 'totalCost' => $newItemCost, 'totalStock' => $newItemStock, 'changeCost' => $changeCost, 'unitCost' => $unitCost];
|
|
|
- });
|
|
|
+ };
|
|
|
+
|
|
|
+ return self::runStockMutation($productId, $callback);
|
|
|
}
|
|
|
|
|
|
|
|
|
//根据数量减库存
|
|
|
public static function decreaseStockByItemNum($productId, $itemNum, $checkStock = false)
|
|
|
{
|
|
|
- return self::runStockMutation($productId, function ($productData) use ($itemNum, $checkStock) {
|
|
|
+ $callback = function ($productData) use ($itemNum, $checkStock) {
|
|
|
$oldStock = $productData->stock;
|
|
|
$newStock = bcsub($oldStock, $itemNum, 2);
|
|
|
if ($checkStock && $newStock < 0) {
|
|
|
@@ -1152,7 +1171,9 @@ class ProductClass extends BaseClass
|
|
|
$productData->save();
|
|
|
|
|
|
return ['oldStock' => $oldStock, 'newStock' => $newStock, 'itemNum' => $itemNum];
|
|
|
- });
|
|
|
+ };
|
|
|
+
|
|
|
+ return self::runStockMutation($productId, $callback);
|
|
|
}
|
|
|
|
|
|
//减少在路上的库存
|
|
|
@@ -1253,7 +1274,7 @@ class ProductClass extends BaseClass
|
|
|
$diffItemIds = array_diff($itemIds, $productDataItemIds);
|
|
|
if ($diffItemIds) {
|
|
|
|
|
|
- $oldProductInfo = ProductClass::getAllByCondition(['id' => ['in', $oldProductIds]], null, '*', 'itemId');
|
|
|
+ $oldProductInfo = self::getAllByCondition(['id' => ['in', $oldProductIds]], null, '*', 'itemId');
|
|
|
|
|
|
//新增到product表,price = itemPrice (出库时的售价), stock=0
|
|
|
foreach ($diffItemIds as $v) {
|
|
|
@@ -1335,7 +1356,7 @@ class ProductClass extends BaseClass
|
|
|
//修改花材商品的库存: 统一方法
|
|
|
public static function updateStockById($id, $stock, $adminId = 0)
|
|
|
{
|
|
|
- return self::runStockMutation($id, function ($productData) use ($stock, $adminId) {
|
|
|
+ $callback = function ($productData) use ($stock, $adminId) {
|
|
|
$productData->stock = $stock;
|
|
|
//如果有库存需要保持上架状态
|
|
|
if ($stock > 0) {
|
|
|
@@ -1345,28 +1366,30 @@ class ProductClass extends BaseClass
|
|
|
$productData->adminId = $adminId;
|
|
|
}
|
|
|
return $productData->save();
|
|
|
- });
|
|
|
+ };
|
|
|
+
|
|
|
+ return self::runStockMutation($id, $callback);
|
|
|
}
|
|
|
|
|
|
//订单退回库存
|
|
|
public static function backStockByOrderItemInfo($orderItemInfo)
|
|
|
{
|
|
|
foreach ($orderItemInfo as $v) {
|
|
|
- ProductClass::addStockByItemNum($v['productId'], $v['itemNum']);
|
|
|
+ self::addStockByItemNum($v['productId'], $v['itemNum']);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//获取当前门店下商品信息 lqh 2021.1.28
|
|
|
public static function getProductData($id, $mainId, $obj = false)
|
|
|
{
|
|
|
- return ProductClass::getByCondition(['id' => $id, 'mainId' => $mainId], $obj);
|
|
|
+ return self::getByCondition(['id' => $id, 'mainId' => $mainId], $obj);
|
|
|
}
|
|
|
|
|
|
//单个修改价格 lqh 2021.1.28
|
|
|
public static function changeSinglePrice($shop, $ptItemId, $price, $skPrice = null, $hjPrice = null, $params = [])
|
|
|
{
|
|
|
$mainId = $shop->mainId ?? 0;
|
|
|
- $productInfo = ProductClass::getByCondition(['itemId' => $ptItemId, 'mainId' => $mainId, 'delStatus' => 0], true);
|
|
|
+ $productInfo = self::getByCondition(['itemId' => $ptItemId, 'mainId' => $mainId, 'delStatus' => 0], true);
|
|
|
if (empty($productInfo)) {
|
|
|
return false;
|
|
|
}
|
|
|
@@ -1676,7 +1699,7 @@ class ProductClass extends BaseClass
|
|
|
}
|
|
|
//增加盘点记录 2021.7.27
|
|
|
$ratio = $product->ratio ?? 0;
|
|
|
- $formNum = ProductClass::formatStock($data['stock'], $ratio);
|
|
|
+ $formNum = self::formatStock($data['stock'], $ratio);
|
|
|
$ghsItemInfo = [['productId' => $product->id, 'bigNum' => $formNum['bigNum'], 'smallNum' => $formNum['smallNum'],]];
|
|
|
$pdData = [];
|
|
|
$pdData['itemInfo'] = $ghsItemInfo;
|
|
|
@@ -2024,7 +2047,7 @@ class ProductClass extends BaseClass
|
|
|
$staffName = $staff->name ?? '';
|
|
|
$changeParams2 = ['staffId' => $staffId, 'staffName' => $staffName];
|
|
|
|
|
|
- $chainProduct = ProductClass::getByCondition(['mainId' => $chainMainId, 'itemId' => $ptItemId], true);
|
|
|
+ $chainProduct = self::getByCondition(['mainId' => $chainMainId, 'itemId' => $ptItemId], true);
|
|
|
if (empty($chainProduct)) {
|
|
|
continue;
|
|
|
}
|
|
|
@@ -2303,7 +2326,7 @@ class ProductClass extends BaseClass
|
|
|
$productData['status'] = 2;
|
|
|
//被归到默认分类,排序值要小,这样在花材列表搜索时,默认分类才不会被排在前面
|
|
|
$productData['inTurn'] = -1;
|
|
|
- $addProduct = ProductClass::addBaseData($productData);
|
|
|
+ $addProduct = self::addBaseData($productData);
|
|
|
$hdProductId = $addProduct->id ?? 0;
|
|
|
|
|
|
//通知新花材需要分类
|
|
|
@@ -2727,7 +2750,7 @@ class ProductClass extends BaseClass
|
|
|
continue;
|
|
|
}
|
|
|
$ids = array_unique(array_filter($ids));
|
|
|
- $productList = ProductClass::getAllByCondition(['id' => ['in', $ids]], null, '*', null, true);
|
|
|
+ $productList = self::getAllByCondition(['id' => ['in', $ids]], null, '*', null, true);
|
|
|
if (!empty($productList)) {
|
|
|
WxMessageClass::stockWarningInform($shop, $productList);
|
|
|
}
|