enterpriseId = $enterpriseId; $this->onLineUserCenterId = $userCenterId; $this->objDInventory = new DInventory('stock'); $this->objDInventoryWarehouse = new DInventoryWarehouse('stock'); $this->objDLockingShop = new DLockingShop('stock'); $this->objDInventoryDetails = new DInventoryDetails('stock'); $this->objDInventoryLocking = new DInventoryLocking('stock'); $this->objDInventoryOutDetails = new DInventoryOutDetails('stock'); $this->objDInventoryBatch = new DInventoryBatch('stock'); $this->objOverviewCache = new OverviewCache(); $this->objInventoryCache = new InventoryCache($this->enterpriseId, $this->onLineUserCenterId); $this->objDInventory->setTable( 'qianniao_inventory_' . $enterpriseId); $this->objDInventoryWarehouse->setTable( 'qianniao_inventory_warehouse_' . $enterpriseId); $this->objDLockingShop->setTable( 'qianniao_locking_shop_' . $enterpriseId); $this->objDInventoryDetails->setSearchIndex('inventory_details_search')->setType('inventory_details'); $this->objDInventoryBatch->setSearchIndex('inventory_batch_search')->setType('inventory_batch'); } /** * 库存流水按照仓库+季度分表 * @param $enterpriseId //公司id * @param $warehouseId //仓库id * @param $tableName * @param int $createTime * @param bool $isReturnTableName //是否返回表名 * @return string * @throws Exception */ public function setDetailsTable($enterpriseId, $warehouseId, $tableName = false, $createTime = 0, $isReturnTableName = false) { if($tableName == false || empty($tableName)){ $tableName = 'qianniao_inventory_details'; } if(!$createTime){ $createTime = time(); } $tableName = $tableName . '_' . $enterpriseId . '_' . $warehouseId . '_' . substr(date('Y', $createTime), -2) . ceil(date('m', $createTime) / 3); if($isReturnTableName) return $tableName; $this->objDInventoryDetails->setTable($tableName); } public function setDetailsTableTerm($createTime = 0) { if(!$createTime) $createTime = time(); return substr(date('Y', $createTime), -2) . ceil(date('m', $createTime) / 3); } /** * 库存批次按照企业商铺分表 * @param $enterpriseId //公司id * @param $warehouseId //仓库id * @param $tableName * @throws Exception */ public function setBatchTable($enterpriseId, $warehouseId, $tableName = false) { if(empty($tableName) || $tableName == false){ $tableName = 'qianniao_inventory_batch'; } $tableName = $tableName . '_' . $enterpriseId . '_' . $warehouseId; $this->objDInventoryBatch->setTable($tableName); } /** * 锁定记录按照季度分表 * @param int $enterpriseId //公司id * @param string $tableName // false 默认 * @param string $time * @throws Exception */ public function setLockingTable($enterpriseId = 0, $tableName = '', $time = '') { if (!$enterpriseId) { $enterpriseId = $this->enterpriseId; } if (empty($tableName) || $tableName == false) { $tableName = 'qianniao_inventory_locking'; } if(!$time){ $time = time(); } $tableName = $tableName . '_' . $enterpriseId . '_' . substr(date('Y', $time), -2) . ceil(date('m', $time) / 3); $this->objDInventoryLocking->setTable($tableName); } /*** * 移动加权计算成本算法 * @param $selectMaterielData array 当前仓库库存数据 * @param $md5Key string md5值 * @param $params array 单据数据 * @param $value array 当前处理的单据明细数据 * @return array */ private function averageCostPrice($selectMaterielData, $md5Key, $params, $value) { //移动加权:(剩余库存数量 * 当前加权成本价 + 本次入库数量 * 本次入库单价) / (剩余库存数量 + 本次入库数量) = 加权成本价 // 判断是否存在库存 if (isset($selectMaterielData[$md5Key])) { //修改库存 $id = $selectMaterielData[$md5Key]['id']; //当前库存数量 $nowInventoryNum = max($selectMaterielData[$md5Key]['inventoryNum'],0); //当前成本 $nowCostPrise = $selectMaterielData[$md5Key]['costPrice']; //当前总价 $nowTotal = bcmul($nowInventoryNum, $nowCostPrise, 4); //入库数量 $inInventoryNum = $value['num']; //入库成本 $inCostPrice = $value['unitPrice']; //入库总价 $inTotal = $value['totalPrice']; //均价成本 $costPrice = bcdiv(bcadd($nowTotal, $inTotal, 4), bcadd($nowInventoryNum, $inInventoryNum, 4), 4); //库存数量 $inventoryNum = bcadd($selectMaterielData[$md5Key]['inventoryNum'], $value['num'], 8); $merchantId = $selectMaterielData[$md5Key]['merchantId']; $otherNum = bcadd($selectMaterielData[$md5Key]['otherNum'], $value['otherNum'], 8); $createTime = $selectMaterielData[$md5Key]['createTime']; $sort = $selectMaterielData[$md5Key]['sort']; } else { //新增库存 $id = null; //当前库存数量 $nowInventoryNum = 0; //当前成本 $nowCostPrise = 0; //当前总价 $nowTotal = 0; //入库数量 $inInventoryNum = $value['num']; //入库成本 $inCostPrice = $value['unitPrice']; //入库总价 $inTotal = $value['totalPrice']; //均价成本 $costPrice = $inCostPrice; //库存数量 $inventoryNum = $value['num']; $merchantId = getArrayItem($params, 'merchantId', 0); $otherNum = $value['otherNum']; $sort = 0; $createTime = time(); } $updateInventoryData = [ 'id' => $id, 'merchantId' => $merchantId, 'inventoryNum' => $inventoryNum, // 累加之后库存 'otherNum' => $otherNum, 'costPrice' => $costPrice, // 移动加权平均单价 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'warehouseId' => $params['warehouseId'], 'skuId' => $value['inventorySkuId'], 'sort' => $sort, 'createTime' => $createTime, 'updateTime' => time(), ]; return $updateInventoryData; } /** * 需要计算成本的入库方式 * @param $params array 单据数据 * @param $inventoreMaster array 物料主库存数据 * @param $selectMaterielData array 物料仓库库存数据 * @param $source int 单据来源 * @param $costType * @return ResultWrapper */ public function calculateCostPrice($params, $inventoryMaster, $selectMaterielData, $source, $costType) { /** * 成本价 = (采购单价 * 采购数量 + (剩余库存数 + 锁定库存数) * 成本价) / (采购数量 + 剩余库存数 + 锁定库存数) * 移动加权平均单价= (本次收入前结存商品金额+本次收入商品金额)/(本次收入前结存商品数量+本次收入商品数量 ) */ $updateInventoryMaster = []; // 更新的主库存数据 $updateWarehouseInventory = [];//更新的仓库库存数据 $addInventoryDetails = []; // 新增的库存流水数据 $addBatchData = []; // 新增批次数据git $inventorySkuIds = []; foreach ($params['Details'] as $key => $value) { //组成md5Key $md5Key = md5($params['warehouseId'] .'+'. $value['inventorySkuId']); // 主库存数据 if( !isset($updateInventoryMaster[$value['inventorySkuId']]) ){ $updateInventoryMaster[$value['inventorySkuId']] = [ 'id' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['id'] : null, 'merchantId' => $params['merchantId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'inventoryNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num']) : $value['num'], 'otherNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum']) : $value['otherNum'], 'lockInventory' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['lockInventory'] : 0, 'skuId' => $value['inventorySkuId'], 'costPrice' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['costPrice'] : 0, 'updateTime' => time(), 'createTime' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['createTime'] : time(), ]; }else{ // 相同skuid 不同批次的进行合并操作 $updateInventoryMaster[$value['inventorySkuId']]['inventoryNum'] = bcadd($updateInventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num']); $updateInventoryMaster[$value['inventorySkuId']]['otherNum'] = bcadd($updateInventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum']); } // 每个仓库库存数据 (按照移动加权计算成本) if( isset($updateWarehouseInventory[$md5Key]) ) { $selectMaterielData[$md5Key] = $updateWarehouseInventory[$md5Key]; } $updateWarehouseInventory[$md5Key] = self::averageCostPrice($selectMaterielData, $md5Key, $params, $value); // 主仓库成本 = 各个仓库成本之和 $updateInventoryMaster[$value['inventorySkuId']]['costPrice'] = bcadd($updateInventoryMaster[$value['inventorySkuId']]['costPrice'], $value['totalPrice'], 4); // 生成入库批次号 有生产日期的用生产日期作为批次号,没有的用系统默认生产的 if( isset($value['productionData']) && !empty($value['productionData']) ){ $batchNo = date('Ymd', $value['productionData']); }else{ $batchNo = createOrderSn(StatusCode::$source['manage'], StatusCode::$orderType['batch'], $this->enterpriseId); } //流水入库批次数据 $batch = json_encode([['batch' => $batchNo, 'num' => $value['num'], 'batchCost' => $value['unitPrice']]]); //流水数据 $addInventoryDetails[] = [ 'warehouseId' => $params['warehouseId'], 'merchantId' => getArrayItem($params, 'merchantId', 0), 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'materielName' => $value['materielName'], 'originId' => $params['originId'], 'originNo' => $params['originNo'], 'sourceNo' => $value['linkNo'], 'source' => $source, 'operatorId' => $params['auditId'], 'operatorName' => $params['auditName'], 'skuId' => $value['inventorySkuId'], 'unitName' => $value['inventoryUnitName'], 'skuName' => $value['skuName'], 'inventoryNum' => $value['num'], 'otherNum' => $value['otherNum'], 'areaId' => $value['areaId'], //库区id 'areaName' => $value['areaName'], //库区名称 'areaCode' => $value['areaCode'], //库区编码 'storageLocationId' => $value['storageLocationId'],//库位id 'storageLocationName' => $value['storageLocationName'],//库位名称 'storageLocationCode' => $value['storageLocationCode'],//库位编码 'inventoryChangeNum' => isset($selectMaterielData[$md5Key]) ? $updateWarehouseInventory[$md5Key]['inventoryNum'] : $value['num'], // 变动后仓库库存数量 'batch' => $batch, // 批次数据 'averageCost' => $updateWarehouseInventory[$md5Key]['costPrice'], 'actionType' => StatusCode::$standard, 'createTime' => time(), 'updateTime' => time(), 'costType' => $costType, ]; //入库批次数据 $addBatchData[] = [ 'merchantId' => $params['merchantId'], 'originId' => $params['originId'], 'originNo' => $params['originNo'], 'warehouseId' => $params['warehouseId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'sourceNo' => $value['linkNo'], 'skuId' => $value['inventorySkuId'], 'batchNo' => $batchNo, 'num' => $value['num'], 'otherNum' => $value['otherNum'], 'areaId' => $value['areaId'], //库区id 'areaName' => $value['areaName'], //库区名称 'areaCode' => $value['areaCode'], //库区编码 'storageLocationId' => $value['storageLocationId'],//库位id 'storageLocationName' => $value['storageLocationName'],//库位名称 'storageLocationCode' => $value['storageLocationCode'],//库位编码 'averageCost' => $updateWarehouseInventory[$md5Key]['costPrice'], 'batchCost' => $value['unitPrice'], 'productionData' => $value['productionData'],//生产日期 'shelfLife' => getArrayItem($value, 'shelfLife', 0),//保质期 'batchStatus' => StatusCode::$standard, 'createTime' => time(), 'updateTime' => time(), ]; } return ResultWrapper::success([ 'updateInventoryData' => array_values($updateInventoryMaster), 'updateWarehouseInventoryData' => array_values($updateWarehouseInventory), 'addInventoryDetails' => $addInventoryDetails, 'addBatchData' => $addBatchData, ]); } /** * 调拨入库方式 * @param $params array 单据数据 * @param $selectMaterielData array 单据中物料已有库存数据 * @param $source int 单据来源 * @param $costType * @return ResultWrapper * @throws Exception */ public function allocateIn($params, $inventoryMaster, $selectMaterielData, $source, $costType) { $updateInventoryMaster = []; // 更新的主库存数据 $updateWarehouseInventory = []; // 更新的仓库库存数据 $addInventoryDetails = []; // 新增得库存流水数据 $updateBatchData = []; // 修改批次数据 $addBatchData = []; // 新增批次数据 // 提取所有单据编号 $allsourceNo = []; $allSkuIds = []; foreach ($params['Details'] as $key => $value) { $allsourceNo[] = $value['linkNo']; $allSkuIds[] = $value['inventorySkuId']; } //切换库存流水表 //要查询调拨出库的流水信息 需要知道调拨出库单的审核时间 = 入库单的创建时间 所以这里用入库单的创建时间 $tableName = 'qianniao_inventory_details_' . $this->enterpriseId . '_' . $params['outWarehouseId'] . '_' . substr(date('Y', $params['createTime']), -2) . ceil(date('m', $params['createTime']) / 3); $this->objDInventoryDetails->setTable($tableName); // 查询出库单对应的出库批次 $condition = [ 'warehouseId' => $params['outWarehouseId'], 'originId' => $params['originId'], 'skuId' => $allSkuIds, 'actionType' => StatusCode::$delete, ]; $dbResult = $this->objDInventoryDetails->select($condition, 'materielName,skuId,sourceNo,inventoryNum,batch,originId'); if ($dbResult === false) { $this->objDInventoryDetails->rollBack(); return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } if (empty($dbResult)) { return ResultWrapper::fail('当前这批物料没有出库记录', ErrorCode::$notAllowAccess); } $outBatchData = []; $outAllBatchNos = []; foreach ($dbResult as $key => $value) { $md5Key = md5($value['originId'] . $value['skuId']); $valueBatch = json_decode($value['batch'], true); $outBatchData[$md5Key] = $valueBatch; foreach ($valueBatch as $k => $v) { $outAllBatchNos[] = $v['batch']; } } // 在入库仓库查询批次数据 $dbResult = $this->objDInventoryBatch->select(['batchNo' => $outAllBatchNos], 'batchNo,id,originId,num,skuId,averageCost,batchCost'); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } $batchData = []; if (!empty($dbResult)) { foreach ($dbResult as $key => $value) { $batchData[$value['batchNo']] = $value; } } // 提取出来所有的物料id $inventorySkuIds = array_column($params['Details'],'inventorySkuId'); // 查询当前这批物料在出库仓库的库存数 $InventoryInfos = $this->objDInventoryWarehouse->select(['skuId' => $inventorySkuIds, 'warehouseId' => $params['outWarehouseId']]); if ($InventoryInfos === false) { return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } // 格式化当前查询出的库存数据 $selectMaterielOutData = []; foreach ($InventoryInfos as $key => $value) { $selectMaterielOutData[md5($value['warehouseId'] .'+'. $value['skuId'])] = $value; } foreach ($params['Details'] as $key => $value) { // 判断在出库仓库中是否有库存记录 $outMd5Key = md5($params['outWarehouseId'] .'+'. $value['inventorySkuId']); if (!isset($selectMaterielOutData[$outMd5Key])) { return ResultWrapper::fail('物料id:' . $value['materielId'] . ' skuId: '.$value['inventorySkuId'].' 在仓库id' . $params['outWarehouseId'] . '中没有库存记录!', ErrorCode::$notAllowAccess); } // 判断在入库仓库中是否有记录 $inMd5Key = md5($params['warehouseId'] .'+'. $value['inventorySkuId']); //仓库数据 $updateWarehouseInventory[] = self::averageCostPrice($selectMaterielData, $inMd5Key, $params, $value); // 生成入库批次号 $batchMd5Key = md5($params['originId'] . $value['inventorySkuId']); if (!isset($outBatchData[$batchMd5Key])) { return ResultWrapper::fail('物料id:' . $value['materielId'] . ' skuId: '.$value['inventorySkuId'].' 在仓库id' . $params['warehouseId'] . '中未出库过!', ErrorCode::$notAllowAccess); } //修改主库存数据 $updateInventoryMaster[] = [ 'id' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['id'] : null, 'merchantId' => isset($inventoryMaster[$value['inventorySkuId']]['merchantId']) ? $inventoryMaster[$value['inventorySkuId']]['merchantId'] : 0, 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'inventoryNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num']) : $value['num'], 'otherNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum']) : $value['otherNum'], 'lockInventory' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['lockInventory'] : 0, 'skuId' => $value['inventorySkuId'], 'costPrice' => bcadd($inventoryMaster[$value['inventorySkuId']]['costPrice'],bcmul($updateWarehouseInventory[$key]['costPrice'], $value['num'], 4),4) , //仓库总成本 = 当前总成本 + 调拨入库总成本 'updateTime' => time(), 'createTime' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['createTime'] : time(), ]; //流水数据 $addInventoryDetails[] = [ 'merchantId' => isset($selectMaterielData[$inMd5Key]['inventoryNum']) ? $selectMaterielData[$inMd5Key]['inventoryNum'] : 0, 'warehouseId' => $params['warehouseId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'materielName' => $value['materielName'], 'sourceNo' => $params['no'], 'source' => $source, 'originId' => $params['originId'], 'originNo' => $params['originNo'], 'operatorId' => $params['auditId'], 'operatorName' => $params['auditName'], 'skuId' => $value['inventorySkuId'], 'unitName' => $value['inventoryUnitName'], 'skuName' => $value['skuName'], 'inventoryNum' => $value['num'], 'otherNum' => $value['otherNum'], 'areaId' => $value['areaId'], //库区id 'areaName' => $value['areaName'], //库区名称 'areaCode' => $value['areaCode'], //库区编码 'storageLocationId' => $value['storageLocationId'],//库位id 'storageLocationName' => $value['storageLocationName'],//库位名称 'storageLocationCode' => $value['storageLocationCode'],//库位编码 'inventoryChangeNum' => isset($updateWarehouseInventory[$key]['id']) ? bcadd($selectMaterielData[$inMd5Key]['inventoryNum'], $value['num'], 8) : $value['num'], // 变动后库存数量 'averageCost' => $updateWarehouseInventory[$key]['costPrice'], 'batch' => json_encode($outBatchData[$batchMd5Key]), // 批次数据 'actionType' => StatusCode::$standard, 'createTime' => time(), 'updateTime' => time(), 'costType' => $costType, ]; // 判断当前出库批次在入库批次是否存在 foreach ($outBatchData[$batchMd5Key] as $batchValue) { if (isset($batchData[$batchValue['batch']])) { //存在 累加 $updateBatchData[] = [ 'id' => $batchData[$batchValue['batch']]['id'], 'num' => bcadd($batchData[$batchValue['batch']]['num'], $value['num'], 8), 'otherNum' => bcadd($batchData[$batchValue['batch']]['otherNum'], $value['otherNum'], 8), 'areaId' => $value['areaId'], //库区id 'areaName' => $value['areaName'], //库区名称 'areaCode' => $value['areaCode'], //库区编码 'storageLocationId' => $value['storageLocationId'],//库位id 'storageLocationName' => $value['storageLocationName'],//库位名称 'storageLocationCode' => $value['storageLocationCode'],//库位编码 'averageCost' => $updateWarehouseInventory[$key]['costPrice'], 'updateTime' => time(), ]; } else { //不存在 新增 $addBatchData[] = [ 'merchantId' => $params['merchantId'], 'originId' => $params['originId'], 'originNo' => $params['originNo'], 'warehouseId' => $params['warehouseId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'sourceNo' => $value['linkNo'], 'skuId' => $value['inventorySkuId'], 'batchNo' => $batchValue['batch'], 'num' => $value['num'], 'otherNum' => $value['otherNum'], 'areaId' => $value['areaId'], //库区id 'areaName' => $value['areaName'], //库区名称 'areaCode' => $value['areaCode'], //库区编码 'storageLocationId' => $value['storageLocationId'],//库位id 'storageLocationName' => $value['storageLocationName'],//库位名称 'storageLocationCode' => $value['storageLocationCode'],//库位编码 'averageCost' => $value['unitPrice'], 'batchCost' => $value['unitPrice'], 'productionData' => isset($value['productionData']) ? $value['productionData'] : 0, 'shelfLife' => $value['shelfLife'], 'batchStatus' => StatusCode::$standard, 'createTime' => time(), 'updateTime' => time(), ]; } } } return ResultWrapper::success([ 'updateInventoryData' => $updateInventoryMaster, 'updateWarehouseInventoryData' => $updateWarehouseInventory, 'addInventoryDetails' => $addInventoryDetails, 'updateBatchData' => $updateBatchData, 'addBatchData' => $addBatchData, ]); } /** * 原路返回入库方式 * @param $params array 单据数据 * @param $selectMaterielData array 单据中物料已有库存数据 * @param $source int 单据来源 * @param $costType * @return ResultWrapper * @throws \Exception */ public function goBack($params, $inventoryMaster, $selectMaterielData, $source, $costType) { $updateInventoryMaster = []; // 更新的主库存数据 $updateWarehouseInventory = []; // 更新的仓库库存数据 $addInventoryDetails = []; // 新增得库存流水数据 $updateBatchData = []; // 修改批次数据 // 提取所有单据编号 $allsourceNo = []; $allSkuIds = []; foreach ($params['Details'] as $key => $value) { $allsourceNo[] = $value['linkNo']; $allSkuIds[] = $value['inventorySkuId']; } //销售退货需要查询 销售出库时生成的流水单据 故按照该销售订单的出库单审核时间 计算表名 if($source == StatusCode::$orderType['saleReturnIn']){ $objMInventoryOut = new MInventoryOut($this->enterpriseId, $this->onLineUserCenterId); $selectInventoryOutWhere = [ 'originId' => $params['originId'], 'deleteStatus' => StatusCode::$standard, 'auditStatus' => StatusCode::$auditStatus['auditPass'], ]; $modelResult = $objMInventoryOut->getInventoryOutData($selectInventoryOutWhere); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $result = $modelResult->getData(); $inventoryOutData = array_shift($result); if(empty($inventoryOutData)){ return ResultWrapper::fail($params['originId'].'出库单据查询失败', ErrorCode::$paramError); } //计算流水表表名 self::setDetailsTable($this->enterpriseId, $params['warehouseId'], false, $inventoryOutData['auditTime']); } // 查询出库单对应的出库批次 $condition = [ 'warehouseId' => $params['warehouseId'], 'originId' => $params['originId'], 'skuId' => $allSkuIds, 'actionType' => StatusCode::$delete, ]; $dbResult = $this->objDInventoryDetails->select($condition, 'materielName,skuId,sourceNo,inventoryNum,batch,originId'); if ($dbResult === false) { $this->objDInventoryDetails->rollBack(); return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } if (empty($dbResult)) { return ResultWrapper::fail('当前这批物料没有出库记录', ErrorCode::$notAllowAccess); } //格式化批次数据 $outBatchData = []; foreach ($dbResult as $key => $value) { $md5Key = md5($value['originId'] .'+'. $value['skuId']); $outBatchData[$md5Key] = json_decode($value['batch'], true); } foreach ($params['Details'] as $key => $value) { $md5Key = md5($params['warehouseId'] .'+'. $value['inventorySkuId']); //判断仓库库存是否存在 if (!isset($selectMaterielData[$md5Key])) { return ResultWrapper::fail('物料id:' . $value['materielId'] . ' skuId: '.$value['inventorySkuId'].' 在仓库id' . $params['warehouseId'] . '中没有库存!', ErrorCode::$notAllowAccess); } //修改主库存 $updateInventoryMaster[] = [ 'id' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['id'] : null, 'merchantId' => $params['merchantId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'inventoryNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num'],8) : $value['num'], 'otherNum' => isset($inventoryMaster[$value['inventorySkuId']]) ? bcadd($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum'], 8) : $value['otherNum'], 'lockInventory' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['lockInventory'] : 0, 'skuId' => $value['inventorySkuId'], 'costPrice' => bcadd($inventoryMaster[$value['inventorySkuId']]['costPrice'], bcmul($selectMaterielData[$md5Key]['costPrice'], $value['num']), 4), // 总成本 = 当前总成本 + 退货总成本 'updateTime' => time(), 'createTime' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['createTime'] : time(), ]; //修改仓库库存 $updateWarehouseInventory[] = [ 'id' => $selectMaterielData[$md5Key]['id'], 'merchantId' => $params['merchantId'], 'materielId' => $value['materielId'], 'warehouseId' => $params['warehouseId'], 'materielCode' => $value['materielCode'], 'inventoryNum' => bcadd($selectMaterielData[$md5Key]['inventoryNum'], $value['num'], 8), // 累加之后库存 'otherNum' => bcadd($selectMaterielData[$md5Key]['otherNum'], $value['otherNum'], 8), // 累加之后库存 'costPrice' => $selectMaterielData[$md5Key]['costPrice'], 'skuId' => $value['inventorySkuId'], 'sort' => $selectMaterielData[$md5Key]['sort'], 'updateTime' => time(), 'createTime' => $selectMaterielData[$md5Key]['createTime'], ]; // 生成入库批次号 $batchMd5Key = md5($params['originId'] .'+'.$value['inventorySkuId']); if (!isset($outBatchData[$batchMd5Key])) { return ResultWrapper::fail('物料id:' . $value['materielId'] . ' skuId: '.$value['inventorySkuId'].' 在仓库id' . $params['warehouseId'] . '中未出库过!', ErrorCode::$notAllowAccess); } // 入库批次 = 出库批次 $addInventoryDetails[] = [ 'merchantId' => $params['merchantId'], 'warehouseId' => $params['warehouseId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'materielName' => $value['materielName'], 'sourceNo' => $params['no'], 'source' => $source, 'originId' => $params['originId'], 'originNo' => $params['originNo'], 'operatorId' => $params['auditId'], 'operatorName' => $params['auditName'], 'skuId' => $value['inventorySkuId'], 'unitName' => $value['inventoryUnitName'], 'skuName' => $value['skuName'], 'inventoryNum' => $value['num'], 'otherNum' => $value['otherNum'], 'inventoryChangeNum' => bcadd($selectMaterielData[$md5Key]['inventoryNum'], $value['num'], 8), // 变动后库存数量 'averageCost' => $selectMaterielData[$md5Key]['costPrice'], // 出库批次成本价 = 当前库存成本价(最后批次成本价) 'batch' => json_encode($outBatchData[$batchMd5Key]), // 批次数据 'actionType' => StatusCode::$standard, 'createTime' => time(), 'updateTime' => time(), 'costType' => $selectMaterielData[$md5Key]['costPrice'], ]; $updateBatchData[] = [ 'batchData' => $outBatchData[$batchMd5Key], 'num' => $value['num'], 'otherNum' => $value['otherNum'], 'updateTime' => time(), ]; } return ResultWrapper::success([ 'updateInventoryData' => $updateInventoryMaster, 'updateWarehouseInventoryData' => $updateWarehouseInventory, 'addInventoryDetails' => $addInventoryDetails, 'updateBatchData' => $updateBatchData, ]); } /** * 销售出库回写出库成本 * @param $data * @param $className */ protected static function backOutCostPrise($data, $className) { file_put_contents('/www/wwwroot/logs/api.junhailan.com/66666666.log', date('Y-m-d H:i:s') . '出库成本回写数据' . var_export($data, true) . PHP_EOL, FILE_APPEND); $i = 1; do { $postData = [ 'topicName' => 'MyJob', 'topicClass' => "Jobs\Model\MTopic\Order\\".$className, 'topicMethon' => 'backOrderOutCostPrise', 'topicMethonParams' => [ 'data' => $data ], ]; $url = QIANNIAO_QUEUE . '/CAddJob/add'; $result = request($url, $postData); $i++; } while ($result['httpcode'] != 200 && $i <= 3); } /** * 库存不足预警 * @param $data * @param $className */ protected static function inventoryNumWarning($data, $className) { $i = 1; do { $postData = [ 'topicName' => 'MyJob', 'topicClass' => "Jobs\Model\MTopic\Message\\".$className, 'topicMethon' => 'inventoryNumWarning', 'topicMethonParams' => [ 'data' => $data ], ]; $url = QIANNIAO_QUEUE . '/CAddJob/add'; $result = request($url, $postData); $i++; } while ($result['httpcode'] != 200 && $i <= 3); } /** * 走锁定得出库方式 * @param $params array 单据数据 * @param $selectMaterielData array 单据中物料已有库存数据 * @param $shopLock array 商铺锁定数据 * @param $source int 单据来源 * @param $costType * @param $outBatchStrategy * @return ResultWrapper * @throws Exception * @throws \Exception */ public function outByLocking($params, $inventoryMaster, $selectMaterielData, $shopLock, $source = 0, $costType, $outBatchStrategy) { // 查询订单创建时间,计算锁定表分表 if(empty($params)){ return ResultWrapper::fail('出库单记录为空', ErrorCode::$contentNotExists); } //计算锁定记录表表名 //查询订单创建时间 $objMOrder = new MOrder($this->onLineUserCenterId, $this->enterpriseId); $result = $objMOrder->getOrderCreateTime($params['originId']); if(!$result->isSuccess()){ return ResultWrapper::fail($result->getData(), $result->getErrorCode()); } $orderIndexData = $result->getData(); if(!isset($orderIndexData['createTime'])){ return ResultWrapper::fail($params['originId'].'的订单创建时间为空', ErrorCode::$notAllowAccess); } // 切换锁定表 self::setLockingTable($this->enterpriseId, false, $orderIndexData['createTime']); //查询锁定记录 $lockingData = []; $dbResult = $this->objDInventoryLocking->select(['shopId' => $params['shopId'], 'originId' => $params['originId'], 'source' => StatusCode::$orderType['saleOrder'], 'lockStatus' => StatusCode::$delete]); if($dbResult === false){ return ResultWrapper::fail($this->objDInventoryLocking->error(), ErrorCode::$dberror); } foreach($dbResult as $value){ $lockingData[$value['skuId']] = $value; } $updateInventoryMaster = []; // 更新的主库存数据 $updateWarehouseInventory = [];//更新的仓库库存数据 $updateShopLock = [];//更新的店铺锁定数据 $addInventoryDetails = []; // 新增得库存流水数据 $downMaterielData = [];//下架商品数据 $updateLockDetailsData = [];//单据锁定记录数据 foreach ($params['Details'] as $key => $value) { $md5Key = md5($params['warehouseId'] .'+'.$value['inventorySkuId']); //判断锁定数量 if(!isset($lockingData[$value['inventorySkuId']]['lockingNum'])){ return ResultWrapper::fail($value['materielName'].'未查询到锁定数据', ErrorCode::$paramError); } if($value['num'] > $lockingData[$value['inventorySkuId']]['lockingNum']){ return ResultWrapper::fail($value['materielName'].'出库数量不能大于锁定数量', ErrorCode::$paramError); } //主库存修改数据 $updateInventoryMaster[] = [ 'id' => $inventoryMaster[$value['inventorySkuId']]['id'], 'merchantId' => $inventoryMaster[$value['inventorySkuId']]['merchantId'], 'materielId' => $inventoryMaster[$value['inventorySkuId']]['materielId'], 'materielCode' => $inventoryMaster[$value['inventorySkuId']]['materielCode'], 'inventoryNum' => $inventoryMaster[$value['inventorySkuId']]['inventoryNum'], 'otherNum' => bcsub($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum'], 8), 'lockInventory' => bcsub($inventoryMaster[$value['inventorySkuId']]['lockInventory'], $value['num'], 8), 'costPrice' => bcsub($inventoryMaster[$value['inventorySkuId']]['costPrice'],bcmul($selectMaterielData[$md5Key]['costPrice'], $value['num'], 4), 4), //出库后总成本 = 仓库总成本 - 出库总成本 'skuId' => $value['inventorySkuId'], 'updateTime' => time(), 'createTime' => $inventoryMaster[$value['inventorySkuId']]['createTime'], ]; //仓库库存修改数据 $updateWarehouseInventory[] = [ 'id' => isset($selectMaterielData[$md5Key]) ? $selectMaterielData[$md5Key]['id'] : null, 'merchantId' => isset($selectMaterielData[$md5Key]['merchantId']) ? $selectMaterielData[$md5Key]['merchantId'] : $inventoryMaster[$value['inventorySkuId']]['merchantId'], 'inventoryNum' => isset($selectMaterielData[$md5Key]) ? bcsub($selectMaterielData[$md5Key]['inventoryNum'], $value['num']) : bcsub(0, $value['num']), //仓库库存=当前仓库库存-出库数量 'otherNum' => isset($selectMaterielData[$md5Key]) ? bcsub($selectMaterielData[$md5Key]['otherNum'], $value['otherNum']) : bcsub(0, $value['otherNum']), //仓库库存=当前仓库库存-出库数量 'costPrice' => isset($selectMaterielData[$md5Key]) ? $selectMaterielData[$md5Key]['costPrice'] : 0, // 移动加权平均单价 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'warehouseId' => $params['warehouseId'], 'skuId' => $value['inventorySkuId'], ]; //店铺锁定数据修改 $updateShopLock[] = [ 'id' => $shopLock[$value['inventorySkuId']]['id'], 'shopId' => $shopLock[$value['inventorySkuId']]['shopId'], 'materielId' => $shopLock[$value['inventorySkuId']]['materielId'], 'materielCode' => $shopLock[$value['inventorySkuId']]['materielCode'], 'skuId' => $shopLock[$value['inventorySkuId']]['skuId'], 'lockInventory' => bcsub($shopLock[$value['inventorySkuId']]['lockInventory'], $value['num'], 8), 'updateTime' => time(), 'createTime' => $shopLock[$value['inventorySkuId']]['createTime'], ]; //删除店铺锁定缓存 $this->objInventoryCache->delShopLock($value['inventorySkuId'], $params['shopId']); //单据锁定记录修改 $updateLockDetailsData[] = [ 'id' => $lockingData[$value['inventorySkuId']]['id'], 'shopId' => $lockingData[$value['inventorySkuId']]['shopId'], 'materielId' => $value['materielId'], 'operatorId' => $lockingData[$value['inventorySkuId']]['operatorId'], 'operatorName' => $lockingData[$value['inventorySkuId']]['operatorName'], 'materielCode' => $lockingData[$value['inventorySkuId']]['materielCode'], 'originId' => $lockingData[$value['inventorySkuId']]['originId'], 'originNo' => $lockingData[$value['inventorySkuId']]['originNo'], 'source' => $lockingData[$value['inventorySkuId']]['source'], 'sourceNo' => $lockingData[$value['inventorySkuId']]['sourceNo'], 'lockingNum' => bcsub($lockingData[$value['inventorySkuId']]['lockingNum'], $value['num'], 8), 'unlockNum' => bcadd($lockingData[$value['inventorySkuId']]['unlockNum'], $value['num'], 8), 'totalNum' => $lockingData[$value['inventorySkuId']]['totalNum'], 'skuId' => $lockingData[$value['inventorySkuId']]['skuId'], 'lockStatus' => bcmul($lockingData[$value['inventorySkuId']]['lockingNum'], $value['num'], 8) > 0 ? 4 : 5, 'unlockTime' => bcmul($lockingData[$value['inventorySkuId']]['lockingNum'], $value['num'], 8) > 0 ? $lockingData[$value['inventorySkuId']]['unlockTime'] : time(), 'createTime' => $lockingData[$value['inventorySkuId']]['createTime'], 'updateTime' => time(), 'extend' => $lockingData[$value['inventorySkuId']]['extend'], ]; //库存为空 下架商品 if ($inventoryMaster[$value['inventorySkuId']]['inventoryNum'] <= 0) { $downMaterielData[] = [ 'shopId' => $params['shopId'], 'materielId' => $value['materielId'] ]; } // 出库策略 $order = 'createTime asc'; if ($outBatchStrategy == 2) { $order = 'createTime desc'; } // 查询当前物料该属性的可用批次记录 $sql = ' warehouseId = ' . $params['warehouseId'] . ' and skuId = ' . $value['inventorySkuId'] . ' and num > 0'; $inventoryBatchData = $this->objDInventoryBatch->select($sql, 'id,batchNo,num,otherNum,skuId,batchCost', $order); if ($inventoryBatchData === false) { return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } $outNum = $value['num'];// 出库数量 $batch = []; // 当前出库用到的所有批次数据 $updateBatchData = []; // 要修改的批次数据 //判断是否有可用批次数据 if(!empty($inventoryBatchData)){ //有可用批次 // 从多个批次中扣除批次可用库存 foreach ($inventoryBatchData as $k => $v) { // 出库数量 = 当前批次数量 if (bccomp($value['num'], $v['num'], 8) == 0) { $batch[] = ['batch' => $v['batchNo'], 'num' => $value['num'], 'batchCost' => $v['batchCost']]; $updateBatchData[] = [ 'id' => $v['id'], 'num' => 0, 'otherNum' => 0, 'updateTime' => time(), ]; break; } // 出库数量 < 当前批次数量 if (bccomp($value['num'], $v['num'], 8) == -1) { $batch[] = ['batch' => $v['batchNo'], 'num' => $value['num'], 'batchCost' => $v['batchCost']]; $updateBatchData[] = [ 'id' => $v['id'], 'num' => bcsub($v['num'], $value['num'], 8), 'otherNum' => bcsub($v['otherNum'], $value['otherNum'], 8), 'updateTime' => time(), ]; break; } // 出库数量 > 当前批次数量 if (bccomp($value['num'], $v['num'], 8) == 1) { $batch[] = ['batch' => $v['batchNo'], 'num' => $v['num'], 'batchCost' => $v['batchCost']]; $updateBatchData[] = [ 'id' => $v['id'], 'num' => '0.00000000', 'otherNum' => '0.00000000', 'updateTime' => time(), ]; $value['num'] = bcsub($value['num'], $v['num'], 8); $value['otherNum'] = bcsub($value['otherNum'], $v['otherNum'], 8); } } } $batch = json_encode($batch); $addInventoryDetails[] = [ 'merchantId' => isset($inventoryMaster[$value['inventorySkuId']]) ? $inventoryMaster[$value['inventorySkuId']]['merchantId'] : 0, 'warehouseId' => $params['warehouseId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'materielName' => $value['materielName'], 'sourceNo' => $params['no'], 'source' => $params['type'], 'originId' => $params['originId'], 'originNo' => $params['originNo'], 'operatorId' => $params['auditId'], 'operatorName' => $params['auditName'], 'skuId' => $value['inventorySkuId'], 'unitName' => $value['unitName'], 'skuName' => $value['skuName'], 'inventoryNum' => $outNum, 'otherNum' => $value['otherNum'], 'inventoryChangeNum' => isset($selectMaterielData[$md5Key]) ? bcsub($selectMaterielData[$md5Key]['inventoryNum'], $outNum) : bcsub(0, $outNum), 'batch' => $batch, 'averageCost' => isset($selectMaterielData[$md5Key]) ? $selectMaterielData[$md5Key]['costPrice'] : 0, // 出库批次成本价 = 当前库存成本价(最后批次成本价) 'areaId' => $value['areaId'], 'areaName' => $value['areaName'], 'areaCode' => $value['areaCode'], 'storageLocationId' => $value['storageLocationId'], 'storageLocationName' => $value['storageLocationName'], 'storageLocationCode' => $value['storageLocationCode'], 'actionType' => StatusCode::$delete, 'createTime' => time(), 'updateTime' => time(), 'costType' => $costType, ]; } return ResultWrapper::success([ 'updateInventoryData' => $updateInventoryMaster, 'updateWarehouseInventoryData' => $updateWarehouseInventory, 'updateShopLock' => $updateShopLock, 'addInventoryDetails' => $addInventoryDetails, 'updateBatchData' => $updateBatchData, 'downMaterielData' => $downMaterielData, 'updateLockDetailsData' => $updateLockDetailsData ]); } /** * 直接减仓库库存的出库 * @param $params array 单据数据 * @param $inventoryMaster array 主库存数据 * @param $selectMaterielData array 仓库库存 * @param $source int 单据来源 * @param $costType * @param $outBatchStrategy * @return ResultWrapper * @throws Exception * @throws \Exception */ public function outByWarehouse($params, $inventoryMaster, $selectMaterielData, $source = 0, $costType, $outBatchStrategy) { $updateInventoryMaster = []; // 更新的主库存数据 $updateWarehouseInventory = [];//更新的仓库库存数据 $addInventoryDetails = []; // 新增得库存流水数据 $downMaterielData = [];//下架商品数据 foreach ($params['Details'] as $key => $value) { $md5Key = md5($params['warehouseId'] .'+'.$value['inventorySkuId']); //判断数量 if($value['num'] > $selectMaterielData[$md5Key]['inventoryNum']){ return ResultWrapper::fail($value['materielName'].'仓库库存不足', ErrorCode::$paramError); } //主库存修改数据 $updateInventoryMaster[] = [ 'id' => $inventoryMaster[$value['inventorySkuId']]['id'], 'merchantId' => $inventoryMaster[$value['inventorySkuId']]['merchantId'], 'materielId' => $inventoryMaster[$value['inventorySkuId']]['materielId'], 'materielCode' => $inventoryMaster[$value['inventorySkuId']]['materielCode'], 'inventoryNum' => bcsub($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num'], 8), 'otherNum' => bcsub($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum'], 8), 'lockInventory' => $inventoryMaster[$value['inventorySkuId']]['lockInventory'], 'costPrice' => bcsub($inventoryMaster[$value['inventorySkuId']]['costPrice'],bcmul($selectMaterielData[$md5Key]['costPrice'], $value['num']),4), // 仓库总成本 = 当前成本 - 调拨出库总成本 'skuId' => $value['inventorySkuId'], 'updateTime' => time(), 'createTime' => $inventoryMaster[$value['inventorySkuId']]['createTime'], ]; //仓库库存修改数据 $updateWarehouseInventory[] = [ 'id' => $selectMaterielData[$md5Key]['id'], 'merchantId' => $selectMaterielData[$md5Key]['merchantId'], 'materielId' => $value['materielId'], 'warehouseId' => $params['warehouseId'], 'materielCode' => $value['materielCode'], 'inventoryNum' => bcsub($selectMaterielData[$md5Key]['inventoryNum'], $value['num']), //仓库库存=当前仓库库存-出库数量 'otherNum' => bcsub($selectMaterielData[$md5Key]['otherNum'], $value['otherNum']), //仓库库存=当前仓库库存-出库数量 'costPrice' => $selectMaterielData[$md5Key]['costPrice'], //移动加权平均单价 'skuId' => $value['inventorySkuId'], 'sort' => $selectMaterielData[$md5Key]['sort'], 'updateTime' => time(), 'createTime' => $selectMaterielData[$md5Key]['createTime'], ]; //库存为空 下架商品 if ($inventoryMaster[$value['inventorySkuId']]['inventoryNum'] <= 0) { $downMaterielData[] = [ 'shopId' => $params['shopId'], 'materielId' => $value['materielId'] ]; } // 出库策略 $order = 'createTime asc'; if ($outBatchStrategy == 2) { $order = 'createTime desc'; } // 查询当前物料该属性的可用批次记录 $sql = ' warehouseId = ' . $params['warehouseId'] . ' and skuId = ' . $value['inventorySkuId'] . ' and num > 0'; $inventoryBatchData = $this->objDInventoryBatch->select($sql, 'id,batchNo,num,otherNum,skuId,batchCost', $order); if ($inventoryBatchData === false) { return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } $outNum = $value['num'];// 出库数量 $batch = []; // 当前出库用到的所有批次数据 $updateBatchData = []; // 要修改的批次数据 //判断是否有可用批次数据 if(!empty($inventoryBatchData)){ //有可用批次 // 从多个批次中扣除批次可用库存 foreach ($inventoryBatchData as $k => $v) { // 出库数量 = 当前批次数量 if (bccomp($value['num'], $v['num'], 8) == 0) { $batch[] = ['batch' => $v['batchNo'], 'num' => $value['num'], 'batchCost' => $v['batchCost']]; $updateBatchData[] = [ 'id' => $v['id'], 'num' => 0, 'otherNum' => 0, 'updateTime' => time(), ]; break; } // 出库数量 < 当前批次数量 if (bccomp($value['num'], $v['num'], 8) == -1) { $batch[] = ['batch' => $v['batchNo'], 'num' => $value['num'], 'batchCost' => $v['batchCost']]; $updateBatchData[] = [ 'id' => $v['id'], 'num' => bcsub($v['num'], $value['num'], 8), 'otherNum' => bcsub($v['otherNum'], $value['otherNum'], 8), 'updateTime' => time(), ]; break; } // 出库数量 > 当前批次数量 if (bccomp($value['num'], $v['num'], 8) == 1) { $batch[] = ['batch' => $v['batchNo'], 'num' => $v['num'], 'batchCost' => $v['batchCost']]; $updateBatchData[] = [ 'id' => $v['id'], 'num' => '0.00000000', 'otherNum' => '0.00000000', 'updateTime' => time(), ]; $value['num'] = bcsub($value['num'], $v['num'], 8); $value['otherNum'] = bcsub($value['otherNum'], $v['otherNum'], 8); } } } $batch = json_encode($batch); $addInventoryDetails[] = [ 'merchantId' => $inventoryMaster[$value['inventorySkuId']]['merchantId'], 'warehouseId' => $params['warehouseId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'materielName' => $value['materielName'], 'sourceNo' => $params['no'], 'source' => $params['type'], 'originId' => $params['originId'], 'originNo' => $params['originNo'], 'operatorId' => $params['auditId'], 'operatorName' => $params['auditName'], 'skuId' => $value['inventorySkuId'], 'unitName' => $value['unitName'], 'skuName' => $value['skuName'], 'inventoryNum' => $outNum, 'otherNum' => $value['otherNum'], 'areaId' => $value['areaId'], //库区id 'areaName' => $value['areaName'], //库区名称 'areaCode' => $value['areaCode'], //库区编码 'storageLocationId' => $value['storageLocationId'],//库位id 'storageLocationName' => $value['storageLocationName'],//库位名称 'storageLocationCode' => $value['storageLocationCode'],//库位编码 'batch' => $batch, 'averageCost' => $selectMaterielData[$md5Key]['costPrice'], // 出库批次成本价 = 当前库存成本价(最后批次成本价) 'actionType' => StatusCode::$delete, 'createTime' => time(), 'updateTime' => time(), 'costType' => $costType, 'inventoryChangeNum' => bcsub($selectMaterielData[$md5Key]['inventoryNum'], $outNum), ]; } return ResultWrapper::success([ 'updateInventoryData' => $updateInventoryMaster, 'updateWarehouseInventoryData' => $updateWarehouseInventory, 'addInventoryDetails' => $addInventoryDetails, 'updateBatchData' => $updateBatchData, 'downMaterielData' => $downMaterielData, ]); } /** * 按照批次出库方式 * @param $params array 单据数据 * @param $selectMaterielData array 单据中物料已有库存数据 * @param $source int 单据来源 * @param $costType * @param $outBatchStrategy * @return ResultWrapper */ public function outByBatch($params, $inventoryMaster, $selectMaterielData, $source, $costType, $outBatchStrategy) { $updateInventoryMaster = []; // 更新的主库存数据 $updateWarehouseInventory = []; // 更新的仓库库存数据 $addInventoryDetails = []; // 新增得库存流水数据 $downMaterielData = [];//下架商品数据 // 查询业务源头对应的所有物料批次信息 $condition = [ 'originId' => $params['originId'], 'warehouseId' => $params['warehouseId'], ]; $dbResult = $this->objDInventoryBatch->select($condition, 'id,materielId,skuId,batchNo,num,averageCost,batchCost'); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } if (empty($dbResult)) { return ResultWrapper::fail('这批出库数据的采购订单物料批次数据为空', ErrorCode::$notAllowAccess); } $batchData = []; $batchTotal = []; foreach ($dbResult as $value) { $md5Key = md5($params['warehouseId'] .'+'. $value['skuId']); $batchTotal[$md5Key] = isset($batchTotal[$md5Key]) ? bcadd($batchTotal[$md5Key], $value['num']) : $value['num']; $batchData[$md5Key][] = $value; } unset($md5Key); foreach ($params['Details'] as $key => $value) { $md5Key = md5($params['warehouseId'] .'+'. $value['inventorySkuId']); // 比较出库数量小于等于批次可用数量 if (bccomp($value['num'], $batchTotal[$md5Key], 8) == 1) { return ResultWrapper::fail($value['materielCode'] . '物料出库数量大于当前批次可用数量', ErrorCode::$notAllowAccess); } //主库存修改数据 $updateInventoryMaster[] = [ 'id' => $inventoryMaster[$value['inventorySkuId']]['id'], 'merchantId' => $inventoryMaster[$value['inventorySkuId']]['merchantId'], 'materielId' => $inventoryMaster[$value['inventorySkuId']]['materielId'], 'materielCode' => $inventoryMaster[$value['inventorySkuId']]['materielCode'], 'inventoryNum' => bcsub($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num'], 8), 'otherNum' => bcsub($inventoryMaster[$value['inventorySkuId']]['otherNum'], $value['otherNum'], 8), 'lockInventory' => $inventoryMaster[$value['inventorySkuId']]['lockInventory'], 'costPrice' => bcsub($inventoryMaster[$value['inventorySkuId']]['costPrice'], bcmul($selectMaterielData[$md5Key]['costPrice'],$value['num']), 4), // 仓库总成本 = 当前总成本 - 出库总成本 'skuId' => $value['inventorySkuId'], 'updateTime' => time(), 'createTime' => $inventoryMaster[$value['inventorySkuId']]['createTime'], ]; //仓库修改数据 $updateWarehouseInventory[] = [ 'id' => $selectMaterielData[$md5Key]['id'], 'merchantId' => $selectMaterielData[$md5Key]['merchantId'], 'materielId' => $value['materielId'], 'warehouseId' => $params['warehouseId'], 'materielCode' => $value['materielCode'], 'inventoryNum' => bcsub($selectMaterielData[$md5Key]['inventoryNum'], $value['num'], 8), // 减掉之后库存 'otherNum' => bcsub($selectMaterielData[$md5Key]['otherNum'], $value['otherNum'], 8), // 减掉之后库存 'costPrice' => $selectMaterielData[$md5Key]['costPrice'], // 移动加权平均单价 'skuId' => $value['inventorySkuId'], 'sort' => $selectMaterielData[$md5Key]['sort'], 'updateTime' => time(), 'createTime' => $selectMaterielData[$md5Key]['createTime'], ]; //商品库存为空 商品下架 if (bcsub($inventoryMaster[$value['inventorySkuId']]['inventoryNum'], $value['num'], 8) <= 0) { $downMaterielData[] = [ 'shopId' => $params['shopId'], 'materielId' => $value['materielId'], ]; } $batch = []; $outNum = $value['num']; $outOtherNum = $value['otherNum']; foreach($batchData[$md5Key] as $batchItem){ if($outNum <= 0){ break; } if($outNum > $batchItem['num']){ //出库数量大于该批次 $batch[] = [ 'batch' => $batchItem['batchNo'], 'num' => $batchItem['num'] ]; $updateBatchData[] = [ 'id' => $batchItem['id'], 'num' => 0, 'otherNum' => bcsub($outOtherNum,$batchItem['otherNum']) < 0 ? 0 : bcsub($outOtherNum,$batchItem['otherNum']),//抄码商品会有问题 (目前统一根据正常单位更改) 'updateTime' => time(), ]; $outNum = bcsub($outNum,$batchItem['num']); $outOtherNum = bcsub($outOtherNum,$batchItem['otherNum']) < 0 ? 0 : bcsub($outOtherNum,$batchItem['otherNum']); }else{ //出库数量 小于等于 该批次 $batch[] = [ 'batch' => $batchItem['batchNo'], 'num' => $outNum ]; $updateBatchData[] = [ 'id' => $batchItem['id'], 'num' => bcsub($batchItem['num'], $outNum, 8), 'otherNum' => bcsub($batchItem['otherNum'], $outOtherNum, 8),//抄码商品会有问题 (目前统一根据正常单位更改) 'updateTime' => time(), ]; $outNum = 0; } } $batch = json_encode($batch); $addInventoryDetails[] = [ 'merchantId' => $inventoryMaster[$value['inventorySkuId']]['merchantId'], 'warehouseId' => $params['warehouseId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'materielName' => $value['materielName'], 'sourceNo' => $params['no'], 'originId' => $params['originId'], 'originNo' => $params['originNo'], 'source' => $params['type'], 'operatorId' => $params['auditId'], 'operatorName' => $params['auditName'], 'skuId' => $value['inventorySkuId'], 'unitName' => $value['inventoryUnitName'], 'skuName' => $value['skuName'], 'inventoryNum' => $value['num'], 'otherNum' => $value['otherNum'], 'inventoryChangeNum' => bcsub($selectMaterielData[$md5Key]['inventoryNum'], $value['num'], 8), // 变动后库存数量 'batch' => $batch, 'averageCost' => $selectMaterielData[$md5Key]['costPrice'], // 出库批次成本价 = 当前库存成本价(最后批次成本价) 'actionType' => StatusCode::$delete, 'createTime' => time(), 'updateTime' => time(), 'costType' => $costType, ]; } return ResultWrapper::success([ 'updateInventoryData' => $updateInventoryMaster, 'updateWarehouseInventoryData' => $updateWarehouseInventory, 'addInventoryDetails' => $addInventoryDetails, 'updateBatchData' => $updateBatchData, 'downMaterielData' => $downMaterielData, ]); } /** * 库存方法 * @param $params array 单据数据 * @param $costType int 成本计算方式 * @param $outBatchStrategy int 出库策略 默认1先进先出 2.后进先出 * @return ResultWrapper * @throws Exception */ public function updateInventory($params, $costType, $outBatchStrategy = 1) { $objMInventoryArea = new MInventoryArea($this->enterpriseId,$this->onLineUserCenterId); // 切换流水详情表 self::setDetailsTable($this->enterpriseId, $params['warehouseId']); // 切换批次表 self::setBatchTable($this->enterpriseId, $params['warehouseId']); // 入库操作单据来源 $inOrderCode = [ StatusCode::$orderType['purchaseIn'],// 3 采购入库 StatusCode::$orderType['saleReturnIn'],// 15 销售退货入库 StatusCode::$orderType['allocateIn'],// 12 调拨入库 StatusCode::$orderType['merchantPurchaseIn'],// 30 商户入库 ]; // 出库操作单据来源 $outOrderCode = [ StatusCode::$orderType['purchaseReturnOut'],// 14 采购退货出库 StatusCode::$orderType['saleOut'],// 5 销售出库 StatusCode::$orderType['allocateOut']// 8调拨出库 ]; if (!isset($params['Details']) || !isset($params['warehouseId'])) { return ResultWrapper::fail('要操作的物料数据或仓库id为空', ErrorCode::$paramError); } // 提取出来所有的物料id $materielIds = array_column($params['Details'],'materielId'); if (empty($materielIds)) { return ResultWrapper::fail('要操作的物料id为空', ErrorCode::$paramError); } // sku单位换算,统一转换为主单位库存数 $modelResult = self::conversionSku($params); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $params = $modelResult->getData(); unset($modelResult); $inventorySkuIds = array_column($params['Details'], 'inventorySkuId'); if(empty($inventorySkuIds)) return ResultWrapper::fail('库存skuId查询失败', ErrorCode::$paramError); //查询物料的总库存 $inventoryResult = $this->objDInventory->select(['skuId' => $inventorySkuIds]); if ($inventoryResult === false) { return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $inventoryMaster = []; foreach ($inventoryResult as $key => $value) { $inventoryMaster[$value['skuId']] = $value; } //查询物料在对应仓库的库存 $InventoryInfos = $this->objDInventoryWarehouse->select(['skuId' => $inventorySkuIds, 'warehouseId' => $params['warehouseId']]); if ($InventoryInfos === false) { return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } $selectMaterielData = []; foreach ($InventoryInfos as $key => $value) { //仓库与主单位md5生成Key $selectMaterielData[md5($value['warehouseId'] .'+'. $value['skuId'])] = $value; } // 所有入库操作 if (in_array($params['type'], $inOrderCode)) { if($params['type'] == StatusCode::$orderType['purchaseIn'] || $params['type'] == StatusCode::$orderType['allocateIn']){ //商品入库设置保质期 $modelResult = self::setInventoryShelfLife($params,$materielIds); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $params = $modelResult->getData(); unset($modelResult); } switch ($params['type']) { case StatusCode::$orderType['purchaseIn']:// 采购入库 $result = self::calculateCostPrice($params, $inventoryMaster, $selectMaterielData, $params['type'], $costType); break; case StatusCode::$orderType['merchantPurchaseIn']:// 商户入库 $result = self::calculateCostPrice($params, $inventoryMaster, $selectMaterielData, $params['type'], $costType); break; case StatusCode::$orderType['allocateIn']: // 调拨入库 $result = self::allocateIn($params, $inventoryMaster,$selectMaterielData, $params['type'], $costType); break; default://销售退货入库 $result = self::goBack($params, $inventoryMaster, $selectMaterielData, $params['type'], $costType); } //组装库存库位数据 foreach ($params['Details'] as $DetailsKey =>$DetailsValue){ if(!empty($DetailsValue['areaId']) && $DetailsValue['storageLocationId'] ){ $areaDate = [ 'warehouseId'=> $params['warehouseId'], 'materielId' => $DetailsValue['materielId'], 'merchantId'=> $params['merchantId'], 'areaId'=> $DetailsValue['areaId'], 'areaName'=> $DetailsValue['areaName'], 'areaCode'=> $DetailsValue['areaCode'], 'storageLocationId'=> $DetailsValue['storageLocationId'], 'storageLocationName'=> $DetailsValue['storageLocationName'], 'storageLocationCode'=> $DetailsValue['storageLocationCode'], 'skuId'=> $DetailsValue['inventorySkuId'], 'unitName'=> $DetailsValue['inventoryUnitName'], 'skuName'=> $DetailsValue['skuName'], 'type'=> StatusCode::$standard, 'num'=> $DetailsValue['num'], ]; $updateAreaResult = $objMInventoryArea->updateInventoryArea($areaDate); if(!$updateAreaResult->isSuccess()){ return ResultWrapper::fail($updateAreaResult->getData(), $updateAreaResult->getErrorCode()); } } } } // 所有出库操作 if (in_array($params['type'], $outOrderCode)) { switch ($params['type']) { case StatusCode::$orderType['saleOut']: // 销售出库 //查询物料的店铺锁定数据 $dbResult = $this->objDLockingShop->select(['shopId' => $params['shopId'], 'skuId' => $inventorySkuIds]); if($dbResult === false){ return ResultWrapper::fail($this->objDLockingShop->error(), ErrorCode::$dberror); } $shopLock = []; foreach($dbResult as $value){ $shopLock[$value['skuId']] = $value; } unset($dbResult); $result = self::outByLocking($params, $inventoryMaster, $selectMaterielData, $shopLock, $params['type'], $costType, $outBatchStrategy); break; case StatusCode::$orderType['allocateOut']: // 调拨出库 $result = self::outByWarehouse($params, $inventoryMaster, $selectMaterielData, $params['type'], $costType, $outBatchStrategy); break; default://采购退货出库 $result = self::outByBatch($params, $inventoryMaster, $selectMaterielData, $params['type'], $costType, $outBatchStrategy); } //组装库存库位数据 foreach ($params['Details'] as $DetailsKey =>$DetailsValue){ if(!empty($DetailsValue['areaId']) && $DetailsValue['storageLocationId'] ){ $areaDate = [ 'warehouseId'=> $params['warehouseId'], 'materielId' => $DetailsValue['materielId'], 'merchantId'=> $params['merchantId'], 'areaId'=> $DetailsValue['areaId'], 'areaName'=> $DetailsValue['areaName'], 'areaCode'=> $DetailsValue['areaCode'], 'storageLocationId'=> $DetailsValue['storageLocationId'], 'storageLocationName'=> $DetailsValue['storageLocationName'], 'storageLocationCode'=> $DetailsValue['storageLocationCode'], 'skuId'=> $DetailsValue['inventorySkuId'], 'unitName'=> $DetailsValue['inventoryUnitName'], 'skuName'=> $DetailsValue['skuName'], 'type'=> StatusCode::$delete, 'num'=> $DetailsValue['num'], ]; $updateAreaResult = $objMInventoryArea->updateInventoryArea($areaDate); if(!$updateAreaResult->isSuccess()){ return ResultWrapper::fail($updateAreaResult->getData(), $updateAreaResult->getErrorCode()); } } } } if (!$result->isSuccess()) { return ResultWrapper::fail($result->getData(), $result->getErrorCode()); } $result = $result->getData(); $addInventoryDetails = $result['addInventoryDetails']; $addBatchData = isset($result['addBatchData']) ? $result['addBatchData'] : []; $updateBatchData = isset($result['updateBatchData']) ? $result['updateBatchData'] : []; $updateInventoryData = $result['updateInventoryData'];//主库存 $updateWarehouseInventoryData = $result['updateWarehouseInventoryData'];//仓库库存 $updateShopLock = isset($result['updateShopLock']) ? $result['updateShopLock'] : []; $downMaterielData = isset($result['downMaterielData']) ? $result['downMaterielData'] : []; $updateLockDetailsData = isset($result['updateLockDetailsData']) ? $result['updateLockDetailsData'] : []; $beginStatus = $this->objDInventory->beginTransaction(); //销售出库回写库存成本 / 生成商户结算单 if($params['type'] == StatusCode::$orderType['saleOut']) self::outInventoryCost($params, $addInventoryDetails, $costType); //库存不足自动预警 self::inventoryNullMessage($addInventoryDetails); //清除库存缓存 self::delCacheInventory($addInventoryDetails); // 修改主库存数据 $dbResult = $this->objDInventory->replace($updateInventoryData, true); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } //修改仓库库存数据 $dbResult = $this->objDInventoryWarehouse->replace($updateWarehouseInventoryData, true); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } //修改商铺锁定数据 if(!empty($updateShopLock)){ $dbResult = $this->objDLockingShop->replace($updateShopLock, true); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDLockingShop->error(), ErrorCode::$dberror); } } //修改锁定记录 if(!empty($updateLockDetailsData)){ $dbResult = $this->objDInventoryLocking->replace($updateLockDetailsData, true); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryLocking->error(), ErrorCode::$dberror); } } // 修改库存流水表数据 unset($dbResult); //流水表插入数据需要重置表名 self::setDetailsTable($this->enterpriseId, $params['warehouseId'], 'qianniao_inventory_details'); $dbResult = $this->objDInventoryDetails->insert($addInventoryDetails, true); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } // 增加es数据 /* $modelResult = self::addEsData($addInventoryDetails, $dbResult); if (!$modelResult->isSuccess()) { $this->objDInventory->rollBack(); return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); }*/ //下架商品 /* if (!empty($downMaterielData)) { $modelResult = self::inventoryNullSetGoodsDown($downMaterielData); if (!$modelResult->isSuccess()) { $this->objDInventory->rollBack(); return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } }*/ // 新增库存批次数据 unset($dbResult); if (isset($addBatchData) && !empty($addBatchData)) { $dbResult = $this->objDInventoryBatch->insert($addBatchData, true); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } //设置批次es数据 /* $modelResult = self::setEsDataByBatch($addBatchData, $dbResult, true); if (!$modelResult->isSuccess()) { $this->objDInventory->rollBack(); return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $esData = $modelResult->getData(); unset($modelResult); //添加es if(!empty($esData)){ foreach ($esData as $value) { //创建es id $esId = parent::setEsId($this->enterpriseId, 'inventoryBatchId', $value['id']); $result = $this->objDInventoryBatch->addUpSearchIndexDocument($value, $esId); $modelResult = parent::isResult($result); if (!$modelResult->isSuccess()) { $this->objDInventory->rollBack(); return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } } }*/ } // 修改批次数据 unset($dbResult); if (isset($updateBatchData) && !empty($updateBatchData)) { foreach ($updateBatchData as $key => $value) { // 通过batchNo去修改 if (isset($value['batchData'])) { foreach ($value['batchData'] as $k => $v) { $sql = 'update ' . $this->objDInventoryBatch->get_Table() . ' set num = ' . $v['num'] . ' + num,updateTime = ' . time() . ' where batchNo = ' . $v['batch']; $dbResult = $this->objDInventoryBatch->query($sql); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } } continue; } // 通过id去修改 $id = $value['id']; unset($value['id']); $dbResult = $this->objDInventoryBatch->update($value, $id); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } } } $beginStatus && $this->objDInventory->commit(); return ResultWrapper::success('操作成功'); } /** * 商品入库设置保质期 * @param $params * @param $materielIds * @return ResultWrapper * @throws Exception */ public function setInventoryShelfLife($params, $materielIds) { // 查询每个物料id对应的保质期 $objMGoodsBasic = new MGoodsBasic($this->onLineUserCenterId, $this->enterpriseId); $modelResult = $objMGoodsBasic->getGoodsDataByGoodsIds($materielIds); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $goodsData = $modelResult->getData(); unset($modelResult); //商品参数加入保质期 foreach ($params['Details'] as $key => &$value) { $value['shelfLife'] = null; $value['specType'] = null; if(isset($goodsData[$value['materielId']])){ $value['shelfLife'] = $goodsData[$value['materielId']]['expireTime']; $value['specType'] = $goodsData[$value['materielId']]['specType']; } } unset($value); return ResultWrapper::success($params); } /** * 清除库存缓存 * @param $addInventoryDetails */ public function delCacheInventory($addInventoryDetails) { foreach($addInventoryDetails as $value){ //出库删除库存redis重置 $this->objInventoryCache->delCacheHash($value['skuId'], $value['warehouseId']); } } /** * 销售出库回写库存成本 * @param $params * @param $addInventoryDetails * @param $costType */ public function outInventoryCost($params,$addInventoryDetails, $costType) { //拼接 $outBatchData['costType'] = $costType;//成本计算方式 $outBatchData['enterpriseId'] = $this->enterpriseId; $outBatchData['userCenterId'] = $this->onLineUserCenterId; $merchantParams = []; foreach($addInventoryDetails as $value){ !isset($outBatchData['originId']) && $outBatchData['originId'] = $value['originId']; $outBatchData['stock'][$value['skuId']]['batch'] = json_decode($value['batch'], true); $outBatchData['stock'][$value['skuId']]['averageCost'] = $value['averageCost']; $outBatchData['stock'][$value['skuId']]['inventoryNum'] = $value['inventoryNum']; if($value['averageCost'] > 0){ $merchantParams[] = [ "orderId" => $value['originId'], "orderNo" => $value['originNo'], "goodsId" => $value['materielId'], "goodsName" => $value['materielName'], "goodsNum" => $value['inventoryNum'], "goodsPrice" => $value['averageCost'], "goodsMoney" => bcmul($value['averageCost'], $value['inventoryNum'],4), "merchantId" => $value['merchantId'], "outStockTime" => $value['createTime'] ]; } } $objMMerchantSettlement = new MMerchantSettlement($this->enterpriseId, $this->onLineUserCenterId); $modelResult = $objMMerchantSettlement->addMerchantSettlement($merchantParams); file_put_contents('/www/wwwroot/logs/api.junhailan.com/9999999.log', date('Y-m-d H:i:s') . '回调数据' . var_export($modelResult->getData(), true) . PHP_EOL, FILE_APPEND); //如果是销售出库 需要把回写成本 if($params['type'] == StatusCode::$orderType['saleOut']){ self::backOutCostPrise($outBatchData, 'MOrder'); } } /** * 设置es数据 * @param $params * @param $ids * @param bool $type //true:新增 默认false:修改 * @return ResultWrapper * @throws \Exception */ public function setEsDataByBatch($params, $ids, $type = false) { if (empty($params) || empty($ids)) return ResultWrapper::success($params); $addData = []; $formatData = parent::formatOrderMan($this->enterpriseId, $params); foreach ($formatData as $key => $value) { $batchData = [ 'id' => isset($ids[$key]) ? $ids[$key] : false, 'enterpriseId' => $this->enterpriseId, 'warehouseId' => isset($value['warehouseId']) ? $value['warehouseId'] : false, 'batchNo' => isset($value['batchNo']) ? $value['batchNo'] : false, 'originId' => isset($value['originId']) ? $value['originId'] : false, 'originNo' => isset($value['originNo']) ? $value['originNo'] : false, 'sourceNo' => isset($value['sourceNo']) ? $value['sourceNo'] : false, 'materielId' => isset($value['materielId']) ? $value['materielId'] : false, 'materielCode' => isset($value['materielCode']) ? $value['materielCode'] : false, 'materielName' => isset($value['materielName']) ? $value['materielName'] : false, 'skuId' => isset($value['skuId']) ? $value['skuId'] : false, 'num' => isset($value['num']) ? $value['num'] : false, 'averageCost' => isset($value['averageCost']) ? $value['averageCost'] : false, 'batchCost' => isset($value['batchCost']) ? $value['batchCost'] : false, 'productionData' => isset($value['productionData']) ? $value['productionData'] : false, 'shelfLife' => isset($value['shelfLife']) ? $value['shelfLife'] : false, 'batchStatus' => isset($value['batchStatus']) ? $value['batchStatus'] : false, 'createTime' => isset($value['createTime']) ? $value['createTime'] : false, 'updateTime' => isset($value['updateTime']) ? $value['updateTime'] : false, ]; foreach ($batchData as $k => $v) { if ($v === false) { if ($type) { return ResultWrapper::fail($k . '---ES字段未设置', ErrorCode::$paramError); } else { unset($batchData[$k]); } } } $addData[] = $batchData; } //创建es id return ResultWrapper::success($addData); } /** * 增加库存数量 */ public function updateIncInventoryNum($params, $costType = 1) { $warehouseId = $params['warehouseId']; $skuData = $params['details']; $updateInventoryMaster = []; // 更新的主库存数据 $updateWarehouseInventory = [];//更新的仓库库存数据 $addInventoryDetails = []; // 新增得库存流水数据 $addBatchData = []; // 新增批次数据 $updateStorageLocation =[]; // 更新库区库位库存表数据 $skuIds = []; foreach($skuData as &$value){ $skuIds[] = $value['skuId']; $value['inventorySkuId'] = $value['skuId']; } unset($value); //查询主库存 $dbResult = $this->objDInventory->select(['skuId' => $skuIds]); if($dbResult === false){ return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $inventoryResult = $dbResult; unset($dbResult); if(empty($inventoryResult)){ return ResultWrapper::fail('未查询到库存数据', ErrorCode::$paramError); } $inventoryMaster = []; foreach($inventoryResult as $value){ $inventoryMaster[$value['skuId']] = $value; } //查询仓库库存 $dbResult = $this->objDInventoryWarehouse->select(['warehouseId' => $warehouseId, 'skuId' => $skuIds]); if($dbResult === false){ return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $inventoryWarehouseResult = $dbResult; unset($dbResult); if(empty($inventoryWarehouseResult)){ return ResultWrapper::fail('未查询到仓库库存数据', ErrorCode::$paramError); } $inventoryWarehouse = []; foreach($inventoryWarehouseResult as $value){ $inventoryWarehouse[$value['skuId']] = $value; } // 查询库区库位仓库表数据 $objDInventoryArea = new DInventoryArea(); $objDInventoryArea->set_Table('qianniao_inventory_area_'.$this->enterpriseId); $condition = [ 'warehouseId'=>$params['warehouseId'], 'merchantId' => getArrayItem($params, 'merchantId', 0), 'skuId'=>$skuIds, ]; $dbResult = $objDInventoryArea->select($condition); if($dbResult === false){ return ResultWrapper::fail($objDInventoryArea->error(), ErrorCode::$dberror); } if(!empty($dbResult)){ // skuid维度映射库区库位库存数据 $inventorystorageLocation = []; foreach($dbResult as $value){ $inventorystorageLocation[$value['skuId']][$value['storageLocationId']] = $value; } } foreach ($skuData as $value) { $skuId = $value['inventorySkuId']; $num = $value['num']; if(!isset($inventoryMaster[$skuId])){ return ResultWrapper::fail('skuId:'.$skuId.'未查询到库存', ErrorCode::$paramError); } if(!isset($inventoryWarehouse[$skuId])){ return ResultWrapper::fail('skuId:'.$skuId.'未查询到仓库库存', ErrorCode::$paramError); } //主库存修改数据 $updateInventoryMaster[] = [ 'id' => $inventoryMaster[$skuId]['id'], 'materielId' => $inventoryMaster[$skuId]['materielId'], 'materielCode' => $inventoryMaster[$skuId]['materielCode'], 'inventoryNum' => bcadd($inventoryMaster[$skuId]['inventoryNum'], $num, 8), 'otherNum' => $value['otherNum'], 'lockInventory' => $inventoryMaster[$skuId]['lockInventory'], 'costPrice' => $inventoryMaster[$skuId]['costPrice'], 'skuId' => $skuId, 'updateTime' => time(), 'createTime' => $inventoryMaster[$skuId]['createTime'], ]; //仓库库存修改数据 $updateWarehouseInventory[] = [ 'id' => $inventoryWarehouse[$skuId]['id'], 'materielId' => $inventoryWarehouse[$skuId]['materielId'], 'warehouseId' => $inventoryWarehouse[$skuId]['warehouseId'], 'materielCode' => $inventoryWarehouse[$skuId]['materielCode'], 'inventoryNum' => bcadd($inventoryWarehouse[$skuId]['inventoryNum'], $num), //仓库库存=当前仓库库存-出库数量 'otherNum' => $value['otherNum'], //仓库库存=当前仓库库存-出库数量 'costPrice' => $inventoryWarehouse[$skuId]['costPrice'], //移动加权平均单价 'skuId' => $inventoryWarehouse[$skuId]['skuId'], 'sort' => $inventoryWarehouse[$skuId]['sort'], 'updateTime' => time(), 'createTime' => $inventoryWarehouse[$skuId]['createTime'], ]; // 库区库位库存修改数据 if( isset($value['storageLocationId']) && !empty($value['storageLocationId']) ){ $updateStorageLocation[] = [ 'id' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['id'], 'materielId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['materielId'], 'warehouseId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['warehouseId'], 'merchantId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['merchantId'], 'areaId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaId'], 'areaName' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaName'], 'areaCode' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaCode'], 'storageLocationId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationId'], 'storageLocationName' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationName'], 'storageLocationCode' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationCode'], 'skuId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['skuId'], 'unitName'=> $inventorystorageLocation[$skuId][$value['storageLocationId']]['unitName'], 'skuName'=> $inventorystorageLocation[$skuId][$value['storageLocationId']]['skuName'], 'num'=> bcadd($inventorystorageLocation[$skuId][$value['storageLocationId']]['num'], $num, 8), 'updateTime'=> time(), ]; } // 生成入库批次号 $batchNo = createOrderSn(StatusCode::$source['manage'], StatusCode::$orderType['batch'], $this->enterpriseId); //流水入库批次数据 $batch = json_encode([['batch' => $batchNo, 'num' => $value['num'], 'batchCost' => $inventoryWarehouse[$skuId]['costPrice']]]); //流水数据 $addInventoryDetails[] = [ 'warehouseId' => $params['warehouseId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'materielName' => $value['materielName'], 'originId' => $params['originId'], 'originNo' => $params['originNo'], 'sourceNo' => $value['linkNo'], 'source' => $params['type'], 'operatorId' => isset($params['auditId'])?$params['auditId']:$params['operatorId'], 'operatorName' => isset($params['auditName'])?$params['auditName']:$params['operatorName'], 'skuId' => $value['inventorySkuId'], 'unitName' => $value['inventoryUnitName'], 'skuName' => $value['skuName'], 'inventoryNum' => $value['num'], 'otherNum' => $value['otherNum'], 'inventoryChangeNum' => bcadd($inventoryWarehouse[$value['skuId']]['inventoryNum'], $value['num'], 8), // 变动后仓库库存数量 'batch' => $batch, // 批次数据 'averageCost' => $inventoryWarehouse[$value['skuId']]['costPrice'], 'actionType' => StatusCode::$standard, 'createTime' => time(), 'updateTime' => time(), 'costType' => $costType, ]; //入库批次数据 $addBatchData[] = [ 'originId' => $params['originId'], 'originNo' => $params['originNo'], 'warehouseId' => $params['warehouseId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'sourceNo' => $value['linkNo'], 'skuId' => $value['inventorySkuId'], 'batchNo' => $batchNo, 'num' => $value['num'], 'otherNum' => $value['otherNum'], 'averageCost' => $inventoryWarehouse[$skuId]['costPrice'], 'batchCost' => $inventoryWarehouse[$skuId]['costPrice'], 'productionData' => 0,//生产日期 'shelfLife' => 0,//保质期 'batchStatus' => StatusCode::$standard, 'createTime' => time(), 'updateTime' => time(), ]; } $beginStatus = $this->objDInventory->beginTransaction(); if(!empty($updateInventoryMaster)){ $dbResult = $this->objDInventory->replace($updateInventoryMaster, true); if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } } if(!empty($updateWarehouseInventory)){ $dbResult = $this->objDInventoryWarehouse->replace($updateWarehouseInventory, true); if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } } if( !empty($updateStorageLocation) ){ $dbResult = $objDInventoryArea->replace($updateStorageLocation, true); if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($objDInventoryArea->error(), ErrorCode::$dberror); } } //直接修改暂时不考虑增加流水 if(!empty($addInventoryDetails)){ self::setDetailsTable($this->enterpriseId, $params['warehouseId'], 'qianniao_inventory_details'); $dbResult = $this->objDInventoryDetails->insert($addInventoryDetails, true); if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } } //添加批次数据 if(!empty($addBatchData)){ $this->objDInventoryBatch->set_Table('qianniao_inventory_batch_'.$this->enterpriseId.'_'.$params['warehouseId']); $dbResult = $this->objDInventoryBatch->insert($addBatchData, true); if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } } //删除缓存 self::delCacheInventory($addInventoryDetails); $beginStatus && $this->objDInventory->commit(); return ResultWrapper::success('操作成功'); } /** * 减少库存数量 */ public function updateDecInventoryNum($params, $outBatchStrategy = 1, $costType = 1) { $warehouseId = $params['warehouseId']; $skuData = $params['details']; $updateInventoryMaster = []; // 更新的主库存数据 $updateWarehouseInventory = [];//更新的仓库库存数据 $addInventoryDetails = []; // 新增得库存流水数据 $updateBatchData = []; // 要修改的批次数据 $updateStorageLocation = []; // 更新库区库位库存数据 // 提取所有skuids $skuIds = []; foreach($skuData as &$value){ $skuIds[] = $value['skuId']; $value['inventorySkuId'] = $value['skuId']; } unset($value); // 查询主库存数据 $dbResult = $this->objDInventory->select(['skuId' => $skuIds]); if($dbResult === false){ return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $inventoryResult = $dbResult; unset($dbResult); if(empty($inventoryResult)){ return ResultWrapper::fail('未查询到库存数据', ErrorCode::$paramError); } // skuId维度映射主库存数据 $inventoryMaster = []; foreach($inventoryResult as $value){ $inventoryMaster[$value['skuId']] = $value; } // 查询仓库库存数据 $dbResult = $this->objDInventoryWarehouse->select(['warehouseId' => $warehouseId, 'skuId' => $skuIds]); if($dbResult === false){ return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $inventoryWarehouseResult = $dbResult; unset($dbResult); if(empty($inventoryWarehouseResult)){ return ResultWrapper::fail('未查询到仓库库存数据', ErrorCode::$paramError); } // skuid维度映射仓库库存数据 $inventoryWarehouse = []; foreach($inventoryWarehouseResult as $value){ $inventoryWarehouse[$value['skuId']] = $value; } // 查询库区库位仓库表数据 $objDInventoryArea = new DInventoryArea(); $objDInventoryArea->set_Table('qianniao_inventory_area_'.$this->enterpriseId); $condition = [ 'warehouseId'=>$params['warehouseId'], 'merchantId' => getArrayItem($params, 'merchantId', 0), 'skuId'=>$skuIds, ]; $dbResult = $objDInventoryArea->select($condition); if($dbResult === false){ return ResultWrapper::fail($objDInventoryArea->error(), ErrorCode::$dberror); } if(!empty($dbResult)){ // skuid维度映射库区库位库存数据 $inventorystorageLocation = []; foreach($dbResult as $value){ $inventorystorageLocation[$value['skuId']][$value['storageLocationId']] = $value; } } // 循环处理盘点单明细数据 foreach ($skuData as $value) { $skuId = $value['inventorySkuId']; $num = $value['num']; if(!isset($inventoryMaster[$skuId])){ return ResultWrapper::fail('skuId:'.$skuId.'未查询到总库存', ErrorCode::$paramError); } if(!isset($inventoryWarehouse[$skuId])){ return ResultWrapper::fail('skuId:'.$skuId.'未查询到仓库库存', ErrorCode::$paramError); } //判断数量 if($num > $inventoryWarehouse[$skuId]['inventoryNum'] || $inventoryWarehouse[$skuId]['inventoryNum'] <= 0 ){ return ResultWrapper::fail( $inventoryWarehouse[$skuId]['materielName'].'仓库库存不足', ErrorCode::$paramError); } //主库存修改数据 $updateInventoryMaster[] = [ 'id' => $inventoryMaster[$skuId]['id'], 'materielId' => $inventoryMaster[$skuId]['materielId'], 'materielCode' => $inventoryMaster[$skuId]['materielCode'], 'inventoryNum' => bcsub($inventoryMaster[$skuId]['inventoryNum'], $num, 8), 'otherNum' => ( $params['type'] == StatusCode::$orderType['stocktaking'] ) ? $value['otherNum'] : bcsub($inventoryMaster[$skuId]['otherNum'], $value['otherNum'], 8), 'lockInventory' => $inventoryMaster[$skuId]['lockInventory'], 'costPrice' => $inventoryMaster[$skuId]['costPrice'], 'skuId' => $skuId, 'updateTime' => time(), 'createTime' => $inventoryMaster[$skuId]['createTime'], ]; //仓库库存修改数据 $updateWarehouseInventory[] = [ 'id' => $inventoryWarehouse[$skuId]['id'], 'materielId' => $inventoryWarehouse[$skuId]['materielId'], 'warehouseId' => $inventoryWarehouse[$skuId]['warehouseId'], 'materielCode' => $inventoryWarehouse[$skuId]['materielCode'], 'inventoryNum' => bcsub($inventoryWarehouse[$skuId]['inventoryNum'], $num), //仓库库存=当前仓库库存-出库数量 'otherNum' => ( $params['type'] == StatusCode::$orderType['stocktaking'] ) ? $value['otherNum'] : bcsub($inventoryWarehouse[$skuId]['otherNum'], $value['otherNum'], 8), 'costPrice' => $inventoryWarehouse[$skuId]['costPrice'], //移动加权平均单价 'skuId' => $inventoryWarehouse[$skuId]['skuId'], 'sort' => $inventoryWarehouse[$skuId]['sort'], 'updateTime' => time(), 'createTime' => $inventoryWarehouse[$skuId]['createTime'], ]; // 库区库位库存修改数据 if( isset($value['storageLocationId']) && !empty($value['storageLocationId']) ){ $updateStorageLocation[] = [ 'id' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['id'], 'materielId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['materielId'], 'warehouseId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['warehouseId'], 'merchantId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['merchantId'], 'areaId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaId'], 'areaName' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaName'], 'areaCode' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['areaCode'], 'storageLocationId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationId'], 'storageLocationName' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationName'], 'storageLocationCode' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['storageLocationCode'], 'skuId' => $inventorystorageLocation[$skuId][$value['storageLocationId']]['skuId'], 'unitName'=> $inventorystorageLocation[$skuId][$value['storageLocationId']]['unitName'], 'skuName'=> $inventorystorageLocation[$skuId][$value['storageLocationId']]['skuName'], 'num'=> bcsub($inventorystorageLocation[$skuId][$value['storageLocationId']]['num'], $num, 8), 'updateTime'=> time(), ]; } // 出库策略 $order = 'createTime asc'; if ($outBatchStrategy == 2) { $order = 'createTime desc'; } // 查询当前物料该属性的可用批次记录 $this->objDInventoryBatch->set_Table('qianniao_inventory_batch_'.$this->enterpriseId.'_'.$warehouseId); $sql = ' warehouseId = ' . $warehouseId . ' and skuId = ' . $skuId . ' and num > 0'; $inventoryBatchData = $this->objDInventoryBatch->select($sql, 'id,batchNo,num,skuId,batchCost', $order); if ($inventoryBatchData === false) { return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } $outNum = $num;// 出库数量 $batch = []; // 当前出库用到的所有批次数据 //判断是否有可用批次数据 if(!empty($inventoryBatchData)){ //有可用批次 // 从多个批次中扣除批次可用库存 foreach ($inventoryBatchData as $k => $v) { // 出库数量 = 当前批次数量 if (bccomp($num, $v['num'], 8) == 0) { $batch[] = ['batch' => $v['batchNo'], 'num' => $num, 'batchCost' => $v['batchCost']]; $updateBatchData[] = [ 'id' => $v['id'], 'num' => 0, 'otherNum' => 0, 'updateTime' => time(), ]; break; } // 出库数量 < 当前批次数量 if (bccomp($num, $v['num'], 8) == -1) { $batch[] = ['batch' => $v['batchNo'], 'num' => $num, 'batchCost' => $v['batchCost']]; $updateBatchData[] = [ 'id' => $v['id'], 'num' => bcsub($v['num'], $num, 8), 'otherNum' => bcsub($v['otherNum'], $value['otherNum'], 8), 'updateTime' => time(), ]; break; } // 出库数量 > 当前批次数量 if (bccomp($num, $v['num'], 8) == 1) { $batch[] = ['batch' => $v['batchNo'], 'num' => $v['num'], 'batchCost' => $v['batchCost']]; $updateBatchData[] = [ 'id' => $v['id'], 'num' => '0.00000000', 'otherNum' => '0.00000000', 'updateTime' => time(), ]; $num = bcsub($num, $v['num'], 8); } } } $batch = json_encode($batch); $addInventoryDetails[] = [ 'warehouseId' => $warehouseId, 'materielId' => $inventoryWarehouse[$skuId]['materielId'], 'materielCode' => $inventoryWarehouse[$skuId]['materielCode'], 'materielName' => $value['materielName'], 'sourceNo' => $params['sourceNo'], 'source' => $params['type'], 'originId' => $params['originId'], 'originNo' => $params['originNo'], 'operatorId' => isset($params['auditId'])?$params['auditId']:$params['operatorId'], 'operatorName' => isset($params['auditName'])?$params['auditName']:$params['operatorName'], 'skuId' => $value['inventorySkuId'], 'unitName' => $value['unitName'], 'skuName' => $value['skuName'], 'inventoryNum' => $outNum, 'otherNum' => $value['otherNum'], 'inventoryChangeNum' => bcsub($inventoryWarehouse[$skuId]['inventoryNum'], $outNum), 'batch' => $batch, 'averageCost' => $inventoryWarehouse[$skuId]['costPrice'], // 出库批次成本价 = 当前库存成本价(最后批次成本价) 'actionType' => StatusCode::$delete, 'createTime' => time(), 'updateTime' => time(), 'costType' => $costType ]; } $beginStatus = $this->objDInventory->beginTransaction(); if(!empty($updateInventoryMaster)){ $dbResult = $this->objDInventory->replace($updateInventoryMaster, true); if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } } if(!empty($updateWarehouseInventory)){ $dbResult = $this->objDInventoryWarehouse->replace($updateWarehouseInventory, true); if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } } if( !empty($updateStorageLocation) ){ $dbResult = $objDInventoryArea->replace($updateStorageLocation, true); if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($objDInventoryArea->error(), ErrorCode::$dberror); } } //直接修改暂时不考虑增加流水 if(!empty($addInventoryDetails)){ //流水表插入数据需要重置表名 self::setDetailsTable($this->enterpriseId, $params['warehouseId'], 'qianniao_inventory_details'); $dbResult = $this->objDInventoryDetails->insert($addInventoryDetails, true); if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } } if(!empty($updateBatchData)){ foreach ($updateBatchData as $key => $value) { // 通过batchNo去修改 if (isset($value['batchData'])) { foreach ($value['batchData'] as $k => $v) { $sql = 'update ' . $this->objDInventoryBatch->get_Table() . ' set num = ' . $v['num'] . ' + num,updateTime = ' . time() . ' where batchNo = ' . $v['batch']; $dbResult = $this->objDInventoryBatch->query($sql); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } } continue; } // 通过id去修改 $id = $value['id']; unset($value['id']); $dbResult = $this->objDInventoryBatch->update($value, $id); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } } } //删除缓存 self::delCacheInventory($addInventoryDetails); $beginStatus && $this->objDInventory->commit(); return ResultWrapper::success('操作成功'); } /** * 仓库期初添加库存 * @param $params * @param $originIds * @return ResultWrapper * @throws Exception */ public function addInventoryByWarehouseBeginning($params, $originIds) { if(empty($params)) return ResultWrapper::fail('库存参数为空', ErrorCode::$paramError); if(empty($originIds)) return ResultWrapper::fail('originIds参数为空', ErrorCode::$paramError); //换算单位 $mobileResult = self::conversionSku(['Details' => $params]); if(!$mobileResult->isSuccess()){ return ResultWrapper::fail($mobileResult->getData(), $mobileResult->getErrorCode()); } $paramsResult = $mobileResult->getData(); unset($mobileResult); $paramsData = $paramsResult['Details']; //查询仓库库存 $skuIds = []; $warehouseId = 0; $materielData = []; foreach($paramsData as $value){ $warehouseId = $value['warehouseId']; $skuIds[] = $value['inventorySkuId']; $materielData[$value['inventorySkuId']] = $value['materielName']; } unset($value); $dbResult = $this->objDInventoryWarehouse->select(['warehouseId' => $warehouseId, 'skuId' => $skuIds]); if($dbResult === false){ return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } $warehouseInventory = $dbResult; unset($dbResult); if(!empty($warehouseInventory)){ $return = ''; foreach($warehouseInventory as $value){ $return .= $materielData[$value['skuId']].','; } return ResultWrapper::fail($return.'在仓库中已有库存', ErrorCode::$paramError); } //查询主库库存 $dbResult = $this->objDInventory->select(['skuId' => $skuIds]); if($dbResult === false){ return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $inventoryResult = $dbResult; unset($dbResult); $inventoryData = []; foreach($inventoryResult as $value){ $inventoryData[$value['skuId']] = $value; } //执行保存 $batchData = []; $inventoryInsert = []; $inventoryWarehouseInsert = []; foreach($paramsData as $key => $value){ $inventoryInsert[] = [ 'id' => isset($inventoryData[$value['inventorySkuId']]) ? $inventoryData[$value['inventorySkuId']]['id'] : null, 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'inventoryNum' => isset($inventoryData[$value['inventorySkuId']]) ? bcadd($inventoryData[$value['inventorySkuId']]['inventoryNum'], $value['num']) : $value['num'], 'lockInventory' => isset($inventoryData[$value['inventorySkuId']]) ? $inventoryData[$value['inventorySkuId']]['lockInventory'] : 0, 'costPrice' => isset($inventoryData[$value['inventorySkuId']]) ? $inventoryData[$value['inventorySkuId']]['costPrice'] : 0, 'skuId' => $value['inventorySkuId'], 'updateTime' => time(), 'createTime' => isset($inventoryData[$value['inventorySkuId']]) ? $inventoryData[$value['inventorySkuId']]['createTime'] : time(), ]; $inventoryWarehouseInsert[] = [ 'warehouseId' => $value['warehouseId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'inventoryNum' => $value['num'], 'costPrice' => $value['costPrice'], 'skuId' => $value['inventorySkuId'], 'updateTime' => time(), 'createTime' => time(), ]; $batchData[] = [ 'originId' => $originIds[$key], 'originNo' => $value['no'], 'warehouseId' => $value['warehouseId'], 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'sourceNo' => $value['no'], 'skuId' => $value['inventorySkuId'], 'batchNo' => createOrderSn(StatusCode::$source['manage'], StatusCode::$orderType['batch'], $this->enterpriseId), 'num' => $value['num'], 'averageCost' => $value['costPrice'], 'batchCost' => $value['costPrice'], //TODO 期初添加的商品需不需要保质期 'productionData' => 0, 'shelfLife' => 0, 'batchStatus' => StatusCode::$standard, 'createTime' => time(), 'updateTime' => time(), ]; } //修改主库库存 $dbResult = $this->objDInventory->replace($inventoryInsert, true); if($dbResult === false){ return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } unset($dbResult); //新增仓库库存 $dbResult = $this->objDInventoryWarehouse->insert($inventoryWarehouseInsert, true); if($dbResult === false){ return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } unset($dbResult); //增加批次 self::setBatchTable($this->enterpriseId, $warehouseId); $dbResult = $this->objDInventoryBatch->insert($batchData, true); if($dbResult === false){ return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } return ResultWrapper::success($dbResult); } /** * sku转换 * @param $data * @return ResultWrapper * @throws Exception */ public function updateNumBySkuId($data) { //传参是单据详情 //循环单据详情 $skuIds = []; foreach ($data as $value) { //查询每条数据的skuId是否是主单位 $skuIds[] = $value['skuId']; } $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId); $modelResult = $objMSku->getNameByIds($skuIds, true); if (!$modelResult->isSuccess()) { return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $skuData = $modelResult->getData(); unset($modelResult); foreach ($data as &$value) { if (isset($skuData[$value['skuId']])) { if ($skuData[$value['skuId']]['isMaster'] == StatusCode::$delete) { // $value['num'] = bcmul($value['num'], $skuData[$value['skuId']]['conversion']);//乘以进率 $value['num'] = bcdiv($value['num'], $skuData[$value['skuId']]['conversion'], 8);//除以进率 } }else{ return ResultWrapper::fail('sku查询错误', ErrorCode::$paramError); } } unset($value); return ResultWrapper::success($data); } /** * 计算sku 转换成主单位 * @param $params //多维数组 商品数据Details 包含参数:materielId, skuId, num * @param array $skuData //多维数组 $skuData[基础资料id] => [skuId => sku表查询的数据] * @return ResultWrapper * @throws Exception */ public function conversionSku($params, $skuData = []) { if(empty($skuData)){ $materielIds = array_column($params['Details'], 'materielId'); $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId); $modelResult = $objMSku->getSkuDataByGoodsIds($materielIds); if (!$modelResult->isSuccess()) { return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $selectSkuData = $modelResult->getData(); unset($modelResult); }else{ $selectSkuData = $skuData; } //$inventorySkuIds = [];//主单位信息数组 foreach ($params['Details'] as $key => &$value) { if(!isset($selectSkuData[$value['materielId']][$value['skuId']])){ return ResultWrapper::fail('商品:'.$value['materielName'].',单位:'.$value['unitName'].(isset($value['skuName']) ? $value['skuName'] : '').',skuId:'.$value['skuId'].'查询失败', ErrorCode::$paramError); } $skuArray = $selectSkuData[$value['materielId']][$value['skuId']]; $value['inventorySkuId'] = $value['skuId'];//库存单位(主单位) 默认当前传来的单位 $value['inventoryUnitName'] = isset($value['unitName']) ? $value['unitName'] : ''; //判断传过来的sku是否是主单位 如果不是 查询同属性主单位skuId的换算比例 if($skuArray['isMaster'] == StatusCode::$delete){ //判断是否有属性 //如果没有属性 对比isMaster = 5 主单位换算比例 $where = [ 'isMaster' => StatusCode::$standard, 'specGroupHash' => '', ]; //如果有属性 对比isMaster = 5 and 哈希 = 此属性的哈希 查出对应属性的主单位换算比例 if($skuArray['specType'] == StatusCode::$specType['multiple']){ $where['specGroupHash'] = $skuArray['specGroupHash']; } $masterSkuData = [];//主单位数据 foreach($selectSkuData[$value['materielId']] as $v){ if(!empty($where['specGroupHash'])){ //有属性 if($v['isMaster'] == $where['isMaster'] && $v['specGroupHash'] == $where['specGroupHash']){ $masterSkuData = $v; } }else{ //没属性 if($v['isMaster'] == $where['isMaster']) { $masterSkuData = $v; } } } if(empty($masterSkuData)){ return ResultWrapper::fail($value['materielName'].'主单位查询失败', ErrorCode::$paramError); } //换算数量 if(isset($skuArray['isNew']) && $skuArray['isNew'] == StatusCode::$standard){ $value['num'] = bcmul($value['num'], $skuArray['conversion'], 8);//乘以进率 }else{ $value['num'] = bcdiv($value['num'], $skuArray['conversion'], 8);//除以进率 } $value['inventorySkuId'] = $masterSkuData['id'];//赋值主单位id $value['inventoryUnitName'] = $masterSkuData['unitName']; } //过滤相同主单位信息 /*if(array_key_exists($value['inventorySkuId'], $inventorySkuIds)){ $params['Details'][$inventorySkuIds[$value['inventorySkuId']]]['num'] = bcadd($params['Details'][$inventorySkuIds[$value['inventorySkuId']]]['num'],$value['num'], 8); unset($params['Details'][$key]); }else{ $inventorySkuIds[$value['inventorySkuId']] = $key; }*/ } unset($value); $params['Details'] = array_values($params['Details']); return ResultWrapper::success($params); } /** * 计算sku 转换成辅单位(把传参里的主单位数量转为辅单位sku的换算后数量(如果传来的sku是主单位则不转)) * @param $params * @return ResultWrapper * @throws Exception */ public function conversionMinorSku($params) { if(empty($params)) return ResultWrapper::success($params); $skuIds = []; foreach($params as $value){ $skuIds[] = $value['skuId']; } $objMSku = new MSku($this->onLineUserCenterId,$this->enterpriseId); $modelResult = $objMSku->getSkuDataBySkuIds($skuIds); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $skuData = $modelResult->getData(); unset($modelResult); foreach($params as &$value){ if(isset($skuData[$value['skuId']]) && isset($skuData[$value['skuId']]['conversion']) && !empty($skuData[$value['skuId']]['conversion']) && $skuData[$value['skuId']]['conversion'] > 0){ if(isset($skuData[$value['skuId']]['isNew']) && $skuData[$value['skuId']]['isNew'] == StatusCode::$standard) { $value['num'] = bcmul($value['num'], $skuData[$value['skuId']]['conversion'], 8);//乘以进率 }else{ $value['num'] = bcdiv($value['num'], $skuData[$value['skuId']]['conversion'], 8);//除以进率 } } } return ResultWrapper::success($params); } /** * 锁定库存锁定 * @param $materielData * @return ResultWrapper * @throws Exception */ public function updateLockInventory($shopId, $materielData) { //换算sku foreach($materielData as &$value){ $value['num'] = $value['lockingNum'];//锁定数量 } unset($value); $params['Details'] = $materielData; $modelResult = self::conversionSku($params); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $formatInventoryNum = $modelResult->getData(); unset($modelResult); $materielData = $formatInventoryNum['Details']; //循环拼接数据 $inventoryLocking = []; $skuIds = []; $materielIds = []; foreach ($materielData as $key => $value) { if (!in_array($value['inventorySkuId'], $skuIds)) { $skuIds[] = $value['inventorySkuId']; } if (!in_array($value['materielId'], $materielIds)) { $materielIds[] = $value['materielId']; } $inventoryLockingData['shopId'] = $shopId; $inventoryLockingData['materielId'] = $value['materielId']; $inventoryLockingData['materielCode'] = createCode(StatusCode::$code['goodsBasic']['prefix'], $value['materielId'], StatusCode::$code['goodsBasic']['length']); $inventoryLockingData['originId'] = $value['originId']; $inventoryLockingData['originNo'] = $value['originNo']; $inventoryLockingData['source'] = $value['source']; $inventoryLockingData['sourceNo'] = $value['sourceNo']; $inventoryLockingData['totalNum'] = $value['num']; $inventoryLockingData['lockingNum'] = $value['num']; $inventoryLockingData['unlockNum'] = 0; $inventoryLockingData['operatorId'] = $value['operatorId']; $inventoryLockingData['operatorName'] = $value['operatorName']; $inventoryLockingData['skuId'] = $value['inventorySkuId']; $inventoryLockingData['createTime'] = time(); $inventoryLockingData['updateTime'] = time(); $inventoryLocking[] = $inventoryLockingData; } //获取负库存设置 $objMGoods = new MGoods($this->enterpriseId, false, $this->onLineUserCenterId); $modelResult = $objMGoods->getDistributionByShopIdRelMaterielIds($shopId, $materielIds); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $preSale = $modelResult->getData(); unset($modelResult); //查询可用库存 $dbResult = $this->objDInventory->select(['skuId' => $skuIds]); if($dbResult === false){ return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $inventoryResult = $dbResult; unset($dbResult); $inventory = []; foreach($inventoryResult as $value){ $inventory[$value['skuId']] = $value; } //查询商铺锁定数据 $dbResult = $this->objDLockingShop->select(['shopId' => $shopId, 'skuId' => $skuIds]); if($dbResult === false){ return ResultWrapper::fail($this->objDLockingShop->error(), ErrorCode::$dberror); } $shopLockResult = $dbResult; unset($dbResult); $shopLock = []; foreach($shopLockResult as $value){ $shopLock[$value['skuId']] = $value['lockInventory']; } $beginStatus = $this->objDInventory->beginTransaction(); foreach ($materielData as $key => $value) { //5.修改主库存数据 if(isset($inventory[$value['inventorySkuId']])){ $update = [ 'inventoryNum' => bcsub($inventory[$value['inventorySkuId']]['inventoryNum'] , $value['num'], 8), 'lockInventory' => bcadd($inventory[$value['inventorySkuId']]['lockInventory'] , $value['num'], 8), 'updateTime' => time(), ]; //判断是否支持预售(负库存销售) if(!isset($preSale[$value['materielId']]) || empty($preSale[$value['materielId']]) || $preSale[$value['materielId']] == StatusCode::$delete){ if($update['inventoryNum'] < 0){ $this->objDInventory->rollBack(); if(isset($value['materielName'])){ return ResultWrapper::fail($value['materielName'].'库存不足', ErrorCode::$paramError); }else{ if(isset($value['goodsName'])){ return ResultWrapper::fail($value['goodsName'].'库存不足', ErrorCode::$paramError); }else{ return ResultWrapper::fail('materielId:' . $value['materielId'] . 'skuId: '.$value['inventorySkuId'].'库存不足', ErrorCode::$paramError); } } } } $dbResult = $this->objDInventory->update($update, ['skuId' => $value['inventorySkuId']]); }else{ //创建库存数据 $insertInventory = [ 'merchantId' => getArrayItem($value, 'merchantId', 0), 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'inventoryNum' => bcsub(0 , $value['num'], 8), 'lockInventory' => $value['num'], 'costPrice' => 0, 'skuId' => $value['inventorySkuId'], 'updateTime' => time(), 'createTime' => time() ]; //判断是否支持预售(负库存销售) if(!isset($preSale[$value['materielId']]) || empty($preSale[$value['materielId']]) || $preSale[$value['materielId']] == StatusCode::$delete){ if($insertInventory['inventoryNum'] < 0){ $this->objDInventory->rollBack(); if(isset($value['materielName'])){ return ResultWrapper::fail($value['materielName'].'库存不足', ErrorCode::$paramError); }else{ if(isset($value['goodsName'])){ return ResultWrapper::fail($value['goodsName'].'库存不足', ErrorCode::$paramError); }else{ return ResultWrapper::fail('materielId:' . $value['materielId'] . 'skuId: '.$value['inventorySkuId'].'库存不足', ErrorCode::$paramError); } } } } $dbResult = $this->objDInventory->insert($insertInventory); } if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } unset($dbResult); //修改商铺锁定数据 if(isset($shopLock[$value['inventorySkuId']])){ $update = [ 'lockInventory' => bcadd($shopLock[$value['inventorySkuId']], $value['num'], 8), 'updateTime' => time(), ]; $dbResult = $this->objDLockingShop->update($update, ['shopId' => $shopId, 'skuId' => $value['inventorySkuId']]); }else{ $insertShopLock = [ 'shopId' => $shopId, 'materielId' => $value['materielId'], 'materielCode' => $value['materielCode'], 'lockInventory' => $value['num'], 'skuId' => $value['inventorySkuId'], 'updateTime' => time(), 'createTime' => time(), ]; $dbResult = $this->objDLockingShop->insert($insertShopLock); } if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDLockingShop->error(), ErrorCode::$dberror); } unset($dbResult); //删除redis $this->objInventoryCache->delShopLock($value['inventorySkuId'], $shopId); } //10.记录锁定流水 self::setLockingTable(); $dbResult = $this->objDInventoryLocking->insert($inventoryLocking, true); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryLocking->error(), ErrorCode::$dberror); } $beginStatus && $this->objDInventory->commit(); return ResultWrapper::success($dbResult); } /** * 解锁物料库存 * @param array $originIds //源头id 订单id * @param int $source //来源 * @param $orderCreateTime 订单创建时间 * @return ResultWrapper * @throws Exception */ public function unlockInventory(array $originIds, $source, $orderCreateTime) { if( empty($originIds) || empty($orderCreateTime) ){ return ResultWrapper::fail('解锁库存参数为空', ErrorCode::$paramError); } // 查询锁定记录 锁定表根据季度分表 self::setLockingTable($this->enterpriseId, false, $orderCreateTime); $dbResult = $this->objDInventoryLocking->select(['originId' => $originIds, 'source' => $source,'lockStatus' => StatusCode::$delete]); if($dbResult === false) { return ResultWrapper::fail($this->objDInventoryLocking->error(), ErrorCode::$dberror); } if(empty($dbResult)) { return ResultWrapper::fail('锁定数据为空01', ErrorCode::$paramError); } $lockData = $dbResult; unset($dbResult); $beginStatus = $this->objDInventory->beginTransaction(); $ids = []; foreach ($lockData as $value) { if($value['lockStatus'] == StatusCode::$standard){ return ResultWrapper::fail('库存已解锁', ErrorCode::$paramError); } $ids[] = $value['id']; $where = [ 'materielId' => $value['materielId'], 'skuId' => $value['skuId'], ]; // 查询总库存表锁定数据 $dbResult = $this->objDInventory->get($where,'lockInventory'); if($dbResult === false){ $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } if(empty($dbResult)){ $this->objDInventory->rollBack(); return ResultWrapper::fail('物料'.$value['materielId'].'skuId:'.$value['skuId'].'库存不存在', ErrorCode::$paramError); } // 如果未解锁过,锁定还未0,则报错 if($dbResult['lockInventory'] <= 0 && $value['unlockNum'] == 0){ $this->objDInventory->rollBack(); return ResultWrapper::fail('物料'.$value['materielId'].'skuId:'.$value['skuId'].'锁定库存不足', ErrorCode::$paramError); } //减去总锁定 $dbResult = $this->objDInventory->set_dec('lockInventory', $where, $value['lockingNum']); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } unset($dbResult); //总库存增加 $dbResult = $this->objDInventory->set_inc('inventoryNum', $where, $value['lockingNum']); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } unset($dbResult); //商铺锁定减少 $dbResult = $this->objDLockingShop->set_dec('lockInventory', ['shopId' => $value['shopId'], 'skuId' => $value['skuId']], $value['lockingNum']); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } unset($dbResult); //删除redis $this->objInventoryCache->delShopLock($value['skuId'], $value['shopId']); } $updateLockData = [ 'lockStatus' => StatusCode::$standard, 'unlockTime' => time(), ]; $dbResult = $this->objDInventoryLocking->update($updateLockData, ['id' => $ids]); if ($dbResult === false) { $this->objDInventory->rollBack(); return ResultWrapper::fail($this->objDInventoryLocking->error(), ErrorCode::$dberror); } $beginStatus && $this->objDInventory->commit(); return ResultWrapper::success('修改成功'); } /** * 根据skuId和shopId获取物料库存数据 * @param array $shopId //$shopId * @param array $skuIds //$skuIds * @return ResultWrapper * @throws \Exception */ public function getInventoryByShopIdAndSkuIds(int $shopId,array $skuIds) { if(empty($shopId)) return ResultWrapper::fail('查询库存shopId参数为空', ErrorCode::$paramError); if(empty($skuIds)) return ResultWrapper::fail('查询库存skuIds参数为空', ErrorCode::$paramError); $inventoryData = []; // 将传过来的skuid统一转换为主单位skuid $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId); $modelResult = $objMSku->getConversion($skuIds); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $skuData = $modelResult->getData(); unset($modelResult); // 查询店铺绑定仓库 $objMShop = new MShop($this->enterpriseId, $this->onLineUserCenterId); $modelResult = $objMShop->getWarehouseIdsByShopId($shopId); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $warehouseIds = $modelResult->getData(); $warehouseIds = array_unique($warehouseIds); unset($modelResult); if( empty($warehouseIds) ){ $return = []; foreach($skuData as $key => $value){ $return[$key]['num'] = 0; $return[$key]['warehouseInventory'] = []; } return ResultWrapper::success($return); } foreach($skuData as $key => $value){ $skuId = $value['masterSkuId']; //查询库存数据 $warehouseInventoryTotal = 0; $warehouseInventoryotherTotal = 0; //查询仓库库存 foreach($warehouseIds as $warehouseId){ $warehouseInventoryNum = 0; $warehouseInventoryOtherNum = 0; $cacheData = $this->objInventoryCache->getCacheHash($skuId, $warehouseId); if(empty($cacheData)){ $dbResult = $this->objDInventoryWarehouse->get(['warehouseId' => $warehouseId, 'skuId' => $skuId]); if($dbResult === false){ return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } $warehouseInventory = $dbResult; unset($dbResult); if(!empty($warehouseInventory)){ $addCache = [ 'materielId' => $warehouseInventory['materielId'], 'warehouseId' => $warehouseId, 'materielCode' => $warehouseInventory['materielCode'], 'inventoryNum' => $warehouseInventory['inventoryNum'], 'otherNum' => $warehouseInventory['otherNum'], 'costPrice' => $warehouseInventory['costPrice'], 'skuId' => $skuId, ]; //保存redis $this->objInventoryCache->addCacheHash($skuId, $addCache); $warehouseInventoryTotal = bcadd($warehouseInventory['inventoryNum'],$warehouseInventoryTotal,8); $warehouseInventoryotherTotal = bcadd($warehouseInventory['otherNum'],$warehouseInventoryotherTotal, 8); $warehouseInventoryNum = $warehouseInventory['inventoryNum']; $warehouseInventoryOtherNum = $warehouseInventory['otherNum']; }else{ $addCache = [ 'warehouseId' => $warehouseId, 'inventoryNum' => 0, 'otherNum' => 0, 'costPrice' => 9, 'skuId' => $skuId, ]; //保存redis $this->objInventoryCache->addCacheHash($skuId, $addCache); } }else{ $warehouseInventoryTotal = bcadd($cacheData['inventoryNum'],$warehouseInventoryTotal, 8); $warehouseInventoryotherTotal = bcadd(getArrayItem($cacheData,'otherNum',0),$warehouseInventoryotherTotal, 8); $warehouseInventoryNum = $cacheData['inventoryNum']; $warehouseInventoryOtherNum = getArrayItem($cacheData,'otherNum',0); } if($warehouseInventoryNum > 0){ if($value['isMaster'] == StatusCode::$standard){ $inventoryData[$key]['warehouseInventory'][$warehouseId]['num'] = $warehouseInventoryNum; $inventoryData[$key]['warehouseInventory'][$warehouseId]['otherNum'] = $warehouseInventoryOtherNum; }else{ if($value['isNew'] == StatusCode::$standard){ $inventoryData[$key]['warehouseInventory'][$warehouseId]['num'] = bcdiv($warehouseInventoryNum, $value['conversion'], 8); $inventoryData[$key]['warehouseInventory'][$warehouseId]['otherNum'] = $warehouseInventoryOtherNum; }else{ $inventoryData[$key]['warehouseInventory'][$warehouseId]['num'] = bcmul($warehouseInventoryNum, $value['conversion'], 8); $inventoryData[$key]['warehouseInventory'][$warehouseId]['otherNum'] = $warehouseInventoryOtherNum; } } }else{ $inventoryData[$key]['warehouseInventory'][$warehouseId]['num'] = 0; $inventoryData[$key]['warehouseInventory'][$warehouseId]['otherNum'] = 0; } } //查询商铺锁定数据 $skuLockNum = 0; $cache = $this->objInventoryCache->getShopLock($shopId, $skuId); if($cache === false){ $dbResult = $this->objDLockingShop->get(['shopId' => $shopId, 'skuId' => $skuId]); if($dbResult === false){ return ResultWrapper::fail($this->objDLockingShop->error(), ErrorCode::$dberror); } if(!empty($dbResult)){ $skuLockNum = $dbResult['lockInventory']; $this->objInventoryCache->addShopLock($shopId, $skuId, $dbResult['lockInventory']); }else{ $this->objInventoryCache->addShopLock($shopId, $skuId, 0); } unset($dbResult); }else{ $skuLockNum = $cache; } $inventoryOtherNum = 0; $inventoryNum = bcsub($warehouseInventoryTotal, $skuLockNum); if($inventoryNum > 0){ if($value['isMaster'] == StatusCode::$standard){ $inventoryData[$key]['num'] = $inventoryNum; }else{ $inventoryOtherNum = bcsub($warehouseInventoryotherTotal, bcdiv($skuLockNum, $value['conversion'], 8)); if($value['isNew'] == StatusCode::$standard){ $inventoryData[$key]['num'] = bcdiv($inventoryNum, $value['conversion'], 8); $inventoryData[$key]['otherNum'] = $inventoryOtherNum; }else{ $inventoryData[$key]['num'] = bcmul($inventoryNum, $value['conversion'], 8); $inventoryData[$key]['otherNum'] = $inventoryOtherNum; } } }else{ $inventoryData[$key]['num'] = 0; $inventoryData[$key]['otherNum'] = 0; } } // 主单位的其他单位 = 辅单位的其他单位 foreach($inventoryData as $key => $value){ if(!isset($value['otherNum'])){ $inventoryData[$key]['otherNum'] = $inventoryOtherNum; } } return ResultWrapper::success($inventoryData); } /** * 根据商铺id和物料ids获取库存信息 * @param $params * @return ResultWrapper */ public function getInventoryByShopIdAndMaterielIds($shopId, $materielIds) { if(empty($shopId)) return ResultWrapper::fail('查询库存shopId参数为空', ErrorCode::$paramError); if(empty($materielIds)) return ResultWrapper::fail('查询库存materielIds参数为空', ErrorCode::$paramError); //查询主单位 $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId); // 根据ids数组获取name $modelResult = $objMSku->getSkuDataByGoodsIds($materielIds, true); if (!$modelResult->isSuccess()) { return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $selectSkuData = $modelResult->getData(); if( empty($selectSkuData) ){ return ResultWrapper::fail('商品主单位异常', ErrorCode::$contentNotExists); } unset($modelResult); $skuIds = []; foreach($selectSkuData as $materielId => $value){ $skuIds = array_merge($skuIds, array_keys($value)); } // 根据skuId和shopId获取物料库存数据 $modelResult = self::getInventoryByShopIdAndSkuIds($shopId, $skuIds); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(),$modelResult->getErrorCode()); } $inventoryData = $modelResult->getData(); $return = []; foreach($selectSkuData as $materielId => $value){ foreach($value as $skuId => $v){ $return[$materielId] = [ 'num' => $inventoryData[$skuId]['num'], 'warehouseInventory' => $inventoryData[$skuId]['warehouseInventory'], 'skuId' => $skuId, 'materielId' => $materielId, 'isMaster' => $v['isMaster'], 'isNew' => $v['isNew'] ]; } } return ResultWrapper::success($return); } /** * 获取库存数据 */ public function getInventoryData($where) { $dbResult = $this->objDInventory->select($where); if($dbResult === false){ return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } return ResultWrapper::success($dbResult); } /** * 查询仓库库存 */ public function getWarehouseInventoryData($warehouseId, $skuIds) { if(!isset($warehouseId)) return ResultWrapper::fail('查询仓库库存warehouseId为空', ErrorCode::$paramError); if(!isset($skuIds)) return ResultWrapper::fail('查询仓库库存skuId为空', ErrorCode::$paramError); //转换单位 $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId); $modelResult = $objMSku->getConversion($skuIds); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $skuData = $modelResult->getData(); unset($modelResult); $masterSkuIds = array_column($skuData, 'masterSkuId'); $where = [ 'warehouseId' => $warehouseId, 'skuId' => $masterSkuIds ]; //查询仓库库存 $dbResult = $this->objDInventoryWarehouse->select($where); if($dbResult === false){ return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } $warehouseInventoryResult = $dbResult; unset($dbResult); if(empty($warehouseInventoryResult)){ return ResultWrapper::fail('仓库库存为空', ErrorCode::$paramError); } $warehouseInventory = []; foreach($warehouseInventoryResult as $value){ $warehouseInventory[$value['skuId']] = $value; } //转换数量 $inventoryData = []; foreach($skuData as $key => $value){ $inventoryNum = $warehouseInventory[$value['masterSkuId']]['inventoryNum']; if($inventoryNum > 0){ if($value['isMaster'] == StatusCode::$standard){ $inventoryData[$key]['num'] = $inventoryNum; }else{ if($value['isNew'] == StatusCode::$standard){ $inventoryData[$key]['num'] = bcdiv($inventoryNum, $value['conversion'], 8); }else{ $inventoryData[$key]['num'] = bcmul($inventoryNum, $value['conversion'], 8); } } }else{ $inventoryData[$key]['num'] = 0; } } return ResultWrapper::success($inventoryData); } /** * 根据goodsIds和仓库ids查询库存 * @param $data * @return ResultWrapper * @deprecated */ public function getInventoryByGoodsIds($data) { if (empty($data)) return ResultWrapper::success($data); $materielIds = array_column($data, 'goodsId'); $warehouseIds = []; foreach($data as $value){ $warehouseIds = array_merge($warehouseIds, $value['warehouseId']); } if(!$materielIds || !$warehouseIds){ return ResultWrapper::fail('查询库存传参错误', ErrorCode::$paramError); } $inventoryData = $this->objDInventory->select(['materielId' => $materielIds, 'warehouseId' => $warehouseIds], 'materielId,warehouseId,inventoryNum,skuId,costPrice'); if ($inventoryData === false) { return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $formatInventoryData = []; $skuInventoryData = []; foreach ($inventoryData as $value) { $md5Key = md5($value['warehouseId'] .'+'. $value['materielId']); $md5SkuKey = md5($value['warehouseId'] .'+'. $value['skuId']); $formatInventoryData[$md5Key]['inventoryNum'] = isset($formatInventoryData[$md5Key]) ? bcadd($formatInventoryData[$md5Key]['inventoryNum'], $value['inventoryNum'], 8) : $value['inventoryNum']; $formatInventoryData[$md5Key]['skuData'][] = $value['skuId']; $skuInventoryData[$md5SkuKey]['inventoryNum'] = $value['inventoryNum']; $skuInventoryData[$md5SkuKey]['materielId'] = $value['materielId']; $skuInventoryData[$md5SkuKey]['skuId'] = $value['skuId']; $skuInventoryData[$md5SkuKey]['inventoryNum'] = $value['inventoryNum']; $skuInventoryData[$md5SkuKey]['warehouseId'] = $value['warehouseId']; $skuInventoryData[$md5SkuKey]['costPrice'] = $value['costPrice']; } foreach ($data as $key => &$value) { $value['num'] = 0; $value['skuData'] = []; foreach($value['warehouseId'] as $v){ $md5Key = md5($v .'+'. $value['goodsId']); if(isset($formatInventoryData[$md5Key])){ $value['num'] = bcadd($value['num'],$formatInventoryData[$md5Key]['inventoryNum']); $skuData = $formatInventoryData[$md5Key]['skuData']; foreach($skuData as $skuId){ $md5SkuKey = md5($v .'+'. $skuId); if(isset($skuInventoryData[$md5SkuKey])){ $value['skuData'][$skuId]['inventoryNum'] = isset($value['skuData'][$skuId]['inventoryNum']) ? bcadd($value['skuData'][$skuId]['inventoryNum'],$skuInventoryData[$md5SkuKey]['inventoryNum']) : $skuInventoryData[$md5SkuKey]['inventoryNum']; $value['skuData'][$skuId]['warehouseInventory'][$v] = $skuInventoryData[$md5SkuKey]; } } } } } return ResultWrapper::success($data); } /** * 根据skuIds查询所有库存 * @param array $skuIds * @return ResultWrapper */ public function getInventoryBySkuIds(array $skuIds) { if(empty($skuIds)) return ResultWrapper::fail('参数为空', ErrorCode::$paramError); $dbResult = $this->objDInventory->select(['skuId'=> $skuIds]); if($dbResult === false){ return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $formatData = []; foreach($dbResult as $value) { $inventoryAllNum = bcadd($value['inventoryNum'], $value['lockInventory'], 8); if(isset($formatData[$value['skuId']])){ $formatData[$value['skuId']] = bcadd($formatData[$value['skuId']],$inventoryAllNum, 8); }else{ $formatData[$value['skuId']] = $inventoryAllNum; } } return ResultWrapper::success($formatData); } /** * 根据materielIds查询所有库存 * @param array $materielIds * @return ResultWrapper */ public function getInventoryByMaterielIds(array $materielIds) { if(empty($materielIds)) return ResultWrapper::fail('参数为空', ErrorCode::$paramError); $dbResult = $this->objDInventory->select(['materielId'=> $materielIds]); if($dbResult === false){ return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $formatData = []; foreach($dbResult as $value) { $inventoryAllNum = bcadd($value['inventoryNum'], $value['lockInventory'], 8); if(isset($formatData[$value['materielId']])){ $formatData[$value['materielId']] = bcadd($formatData[$value['materielId']],$inventoryAllNum, 8); }else{ $formatData[$value['materielId']] = $inventoryAllNum; } } return ResultWrapper::success($formatData); } /** * 根据物料ids查询库存物料剩余数量 * @param $materielData * @return ResultWrapper */ public function getNumByMaterielIds($materielData) { $where = [ 'warehouseId' => [], 'materielId' => [], ]; foreach ($materielData as $key => $value) { if (!in_array($value['warehouseId'], $where['warehouseId'])) { $where['warehouseId'][] = $value['warehouseId']; } $where['materielId'][] = $value['materielId']; } $dbResult = $this->objDInventory->select($where, 'materielId,warehouseId,inventoryNum,lockInventory'); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $formatData = []; foreach ($dbResult as $key => $value) { $formatData[$value['warehouseId']][$value['materielId']]['inventoryNum'] = $value['inventoryNum']; $formatData[$value['warehouseId']][$value['materielId']]['lockInventory'] = $value['lockInventory']; } return ResultWrapper::success($formatData); } /** * 库存详情 * @param $params * @return ResultWrapper */ public function getInventoryInfo($params) { //注意!!!! 获取详情需要按照创建日期重新获取表名 $params['deleteStatus'] = StatusCode::$standard; $dbResult = $this->objDInventory->get($params); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $dbResult['orderGoodsData'] = $this->objDInventoryDetails->select(['InventoryId' => $dbResult['id']]); if ($dbResult['orderGoodsData'] === false) { return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } return ResultWrapper::success($dbResult); } /** * 库存查询列表 * @param $selectParams * @param $export * @return ResultWrapper * @throws Exception */ public function getInventoryAll($selectParams, $export = 0) { $limit = $selectParams['limit']; unset($selectParams['limit']); $offset = $selectParams['offset']; unset($selectParams['offset']); if($export){ $limit = 99999; $offset = 0; } if ((isset($selectParams['materielName']) && !empty($selectParams['materielName'])) || (isset($selectParams['categoryId']) && !empty($selectParams['categoryId']))) { $objDGoodsBasic = new DGoodsBasic('default'); $objDGoodsBasic->setTable( 'qianniao_goods_basic_' . $this->enterpriseId); $sql = 'select id from '.$objDGoodsBasic->get_Table().' where '; $whereSql = ''; if( isset($selectParams['materielName']) && !empty($selectParams['materielName']) ){ $whereSql .= (!empty($whereSql) ? ' and ' : '').' title like "%' . $selectParams['materielName'] . '%" '; } if( isset($selectParams['categoryId']) && !empty($selectParams['categoryId']) ){ $whereSql .= (!empty($whereSql) ? ' and ' : '')." FIND_IN_SET('".$selectParams['categoryId']."',categoryPath) "; } if( isset($selectParams['merchantId']) && $selectParams['merchantId'] != 0 ){ $whereSql .= (!empty($whereSql) ? ' and ' : '').' merchantId = ' . $selectParams['merchantId']; } $sql = $sql.$whereSql; $dbResult = $objDGoodsBasic->query($sql); if ($dbResult === false) { return ResultWrapper::fail($objDGoodsBasic->error(), ErrorCode::$dberror); } $selectParams['materielId'] = []; foreach ($dbResult as $value) { $selectParams['materielId'][] = $value['id']; } unset($selectParams['materielName']); unset($selectParams['categoryId']); if (empty($selectParams['materielId'])) { $return['amount'] = 0; $return['count'] = 0; $return['data'] = []; $return['total'] = 0; return ResultWrapper::success($return); } } //拼接sql $sql = 'select * from qianniao_inventory_'.$this->enterpriseId; $whereSql = ''; if( isset($selectParams['materielId']) && !empty($selectParams['materielId']) ){ $whereSql .= (empty($whereSql) ? '' : ' and ').' materielId in('.implode(',', $selectParams['materielId']).')'; } if( isset($selectParams['materielId']) && !empty($selectParams['materielId']) ){ $whereSql .= (empty($whereSql) ? '' : ' and ').' materielId in('.implode(',', $selectParams['materielId']).')'; } if( isset($selectParams['merchantId']) && $selectParams['merchantId'] != 0 ){ $whereSql .= (empty($whereSql) ? '' : ' and ').' merchantId = '.$selectParams['merchantId']; } if( isset($selectParams['haveInventoryNum']) && !empty($selectParams['haveInventoryNum']) ){ switch ($selectParams['haveInventoryNum']) { case StatusCode::$standard; // 只查询有库存数量和锁定数量的数据 $whereSql .= (empty($whereSql) ? '' : ' and ').'( inventoryNum >= 0 )'; break; case StatusCode::$delete;// 只查询没有库存数量和锁定数量的数据 $whereSql .= (empty($whereSql) ? '' : ' and ').' inventoryNum = 0 and lockInventory = 0 '; break; case StatusCode::$partion;//只查询库存为负数的数据 $whereSql .= (empty($whereSql) ? '' : ' and ').' inventoryNum < 0 '; break; } } if( isset($selectParams['materielCode']) && !empty($selectParams['materielCode']) ){ $whereSql .= (empty($whereSql) ? '' : ' and ').' materielCode = "'.$selectParams['materielCode'].'"'; } !empty($whereSql) && $whereSql = ' where '.$whereSql; $orderSql = ' order by createTime desc'; if( isset($selectParams['sortType']) ){ switch (true){ case $selectParams['sortType'] ==0; $orderSql = ' order by createTime desc'; break; case $selectParams['sortType'] ==1; $orderSql = ' order by inventoryNum desc'; break; case $selectParams['sortType'] ==2; $orderSql = ' order by inventoryNum asc'; break; case $selectParams['sortType'] ==3; $orderSql = ' order by lockInventory desc'; break; case $selectParams['sortType'] ==4; $orderSql = ' order by lockInventory asc'; break; } } $limitSql = ' limit '.$offset.','.$limit; $sql = $sql.$whereSql.$orderSql.$limitSql; $dbResult = $this->objDInventory->query($sql); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $sql = "select count(materielId) as count,sum(costPrice) as totalCostPrice from " . $this->objDInventory->get_Table(); if(isset($selectParams['merchantId'])){ $sql .= ' where merchantId = '.$selectParams['merchantId']; } $totalData = $this->objDInventory->query($sql); if ($totalData === false) { return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $amount = 0; $count = 0; if (!empty($totalData)) { $shiftData = array_shift($totalData); $count = $shiftData['count']; $amount = $shiftData['totalCostPrice']; } $sql = 'select count(*) as count from qianniao_inventory_'.$this->enterpriseId.$whereSql; $totalResult = $this->objDInventory->query($sql); if ($totalResult === false) { return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $total = isset($totalResult[0]) ? $totalResult[0]['count'] : 0; $formatData = parent::formatOrderMan($this->enterpriseId, $dbResult); $modelResult = self::formatSkuNum($formatData); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $return['data'] = $modelResult->getData(); $return['amount'] = $amount; $return['count'] = $count; $return['total'] = $total; if ($export) { // $dbResult = $this->objDInventory->select($selectParams, '*', 'id desc'); // if ($dbResult === false) { // return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); // } // $modelResult = self::formatSkuNum($dbResult); // if(!$modelResult->isSuccess()){ // return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); // } self::exportInventory($return['data']); exit; } if ($return === false) { return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $this->updateCache = true; return ResultWrapper::success($return); } /** * 仓库库存 */ public function getWarehouseInventory($params) { $sql = 'select i.materielId,i.materielCode,i.skuId,i.inventoryNum,i.inventoryNum * i.costPrice as total,i.costPrice,i.warehouseId,i.createTime,i.updateTime,w.warehouseName,w.id as warehouseId from qianniao_inventory_warehouse_'.$this->enterpriseId.' i left join qianniao_warehouse_'.$this->enterpriseId.' w on i.warehouseId = w.id where i.skuId = '.$params['skuId'].' order by i.sort,i.createTime desc'; $dbResult = $this->objDInventory->query($sql); if($dbResult === false){ return ResultWrapper::fail($this->objDInventory->error(), ErrorCode::$dberror); } $formatData = parent::formatOrderMan($this->enterpriseId, $dbResult); $modelResult = self::formatSkuNum($formatData); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $return = $modelResult->getData(); return ResultWrapper::success($return); } /** * 格式化skuNum * @param $params //二维数组 * @param string $materielIdKey //商品基础资料id的key * @param string $inventoryNumKey //商品数量的key * @param string $skuIdKey //商品skuId的key * @return ResultWrapper * @throws \Exception */ public function formatSkuNum($params, $materielIdKey = 'materielId', $inventoryNumKey = 'inventoryNum', $skuIdKey = 'skuId') { if(empty($params)) return ResultWrapper::success($params); //获取所有基础资料id $materielIds = array_column(array_values($params), $materielIdKey); $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId); //获取所有skuIds $modelResult = $objMSku->getSkuDataByGoodsIds($materielIds); if (!$modelResult->isSuccess()) { return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $skuData = $modelResult->getData(); unset($modelResult); foreach($params as &$value){ $value['skuValue'] = ''; $value['skuNum'] = '0'; //取出sku数据 if(isset($skuData[$value[$materielIdKey]]) && isset($skuData[$value[$materielIdKey]][$value[$skuIdKey]])){ //获取当前单位sku $selectSkuData = $skuData[$value[$materielIdKey]][$value[$skuIdKey]]; $skuParam = []; $masterSku = [];//主单位 //获取所有sku foreach($skuData[$value[$materielIdKey]] as $v){ if($v['isMaster'] == StatusCode::$delete){ if($selectSkuData['specType'] == 2){ //有属性 比对哈希 找出同类型单位 if($v['specGroupHash'] == $selectSkuData['specGroupHash']){ $skuParam[] = $v; } }else{ //无属性 都是同类型单位 $skuParam[] = $v; } }else{ $v['conversion'] = 1; $skuParam[] = $v; $masterSku = $v; } } if(!empty($skuParam)){ //重新排序sku $conversions = array_column($skuParam,'conversion'); if($masterSku['isNew'] == StatusCode::$standard){ $order = SORT_DESC; }else{ $order = SORT_ASC; } array_multisort($conversions,$order,$skuParam); //最小单位 $smallSku = array_pop($skuParam); $skuParam[] = $smallSku; //主单位换算比例修改 if($selectSkuData['isMaster'] == StatusCode::$standard){ $selectSkuData['conversion'] = 1; } //主单位数量 if($masterSku['isNew'] == StatusCode::$standard){ //新 //辅换主 乘 $masterNum = bcmul($value[$inventoryNumKey], $selectSkuData['conversion']);//主单位数量 //主换辅 除 $smallNum = bcdiv($masterNum, $smallSku['conversion']);//最小单位数量 }else{ //旧 //辅换主 除 $masterNum = bcdiv($value[$inventoryNumKey], $selectSkuData['conversion']);//主单位数量 //主换辅 乘 $smallNum = bcmul($masterNum, $smallSku['conversion']);//最小单位数量 } foreach($skuParam as $sku){ //拼接比例 if($sku['isMaster'] == StatusCode::$delete){ if($masterSku['isNew'] == StatusCode::$standard) { $skuValues = '1'.$sku['unitName'].'='.floatval($sku['conversion']).$masterSku['unitName']; }else{ $skuValues = '1'.$masterSku['unitName'].'='.floatval($sku['conversion']).$sku['unitName']; } $value['skuValue'] .= (empty($value['skuValue']) ? '':'/').$skuValues; } if($masterSku['isNew'] == StatusCode::$standard){ //新 $conversion = bcdiv($sku['conversion'], $smallSku['conversion']); }else{ //旧 $conversion = bcdiv($smallSku['conversion'], $sku['conversion']); } $skuNum = intval(bcdiv($smallNum , $conversion)); //计算数量 if($skuNum > 0){ $smallNum = $smallNum % $conversion; $value['skuNum'] == '0' && $value['skuNum'] = ''; $value['skuNum'] .= floatval($skuNum).$sku['unitName']; } } } } } return ResultWrapper::success($params); } /** * 换算sku数量 * @param $params * @return ResultWrapper * @throws \Exception */ public function getSkuNum($params) { $modelResult = self::formatSkuNum($params,'goodsBasicId','num','skuId'); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $data = $modelResult->getData(); unset($modelResult); $return = []; foreach($data as $value){ $return[$value['skuId']] = $value; } return ResultWrapper::success($return); } /** * 换算主单位sku数量 * @param $params * @return ResultWrapper * @throws \Exception */ public function getMasterSkuNum($params) { $modelResult = self::formatMasterSkuNum($params,'goodsBasicId','num','skuId'); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $data = $modelResult->getData(); unset($modelResult); $return = []; foreach($data as $value){ $return[$value['skuId']] = $value; } return ResultWrapper::success($return); } /** * 换算主单位sku数量 * @param $params * @param string $materielIdKey * @param string $inventoryNumKey * @param string $skuIdKey * @return ResultWrapper * @throws \Exception */ public function formatMasterSkuNum($params, $materielIdKey = 'materielId', $inventoryNumKey = 'inventoryNum', $skuIdKey = 'skuId') { //获取所有基础资料id $materielIds = array_column(array_values($params), $materielIdKey); $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId); //获取所有skuIds $modelResult = $objMSku->getSkuDataByGoodsIds($materielIds); if (!$modelResult->isSuccess()) { return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $skuData = $modelResult->getData(); unset($modelResult); foreach($params as &$value){ $value['masterNum'] = 0; $value['masterName'] = ''; $value['skuNum'] = 0; $value['skuValue'] = ''; $value['skuName'] = ''; $value['title'] = ''; if(isset($skuData[$value[$materielIdKey]])){ $skuParam = $skuData[$value[$materielIdKey]][$value[$skuIdKey]]; $value['masterName'] = $skuParam['unitName']; $value['masterNum'] = floatval($value[$inventoryNumKey]); $value['skuNum'] = $value[$inventoryNumKey]; $value['skuName'] = $skuParam['unitName']; if($skuParam['isMaster'] == StatusCode::$delete){ if($skuParam['isNew'] == StatusCode::$standard){ //新 乘 $value['masterNum'] = floatval(bcmul($value[$inventoryNumKey], $skuParam['conversion'], 2)); $value['skuNum'] = bcdiv($value['masterNum'], $skuParam['conversion'], 2); }else{ //旧 除 $value['masterNum'] = floatval(bcdiv($value[$inventoryNumKey], $skuParam['conversion'], 2)); $value['skuNum'] = bcmul($value['masterNum'], $skuParam['conversion'], 2); } $skuArray = $skuData[$value[$materielIdKey]]; $masterSku = []; foreach($skuArray as $v){ if($v['isMaster'] == StatusCode::$standard){ $masterSku = $v; } } $value['masterName'] = $masterSku['unitName']; if($skuParam['isNew'] == StatusCode::$standard) { $value['skuValue'] = '1'.$skuParam['unitName'].'='.floatval($skuParam['conversion']).$masterSku['unitName']; }else{ $value['skuValue'] = '1'.$masterSku['unitName'].'='.floatval($skuParam['conversion']).$skuParam['unitName']; } } } if($value[$inventoryNumKey] != $value['skuNum']){ $value['title'] = $value['skuValue'].','.$value[$inventoryNumKey].$value['skuName'].'无法换算为'.$value['masterName'].',请输入正确的数量(换算比例的倍数)'; $value[$inventoryNumKey] = 0; } } return ResultWrapper::success($params); } /** * 库存导出方法 * @param $result * @return void * @throws Exception */ public function exportInventory($result) { //导出到本地 header("Content-type:application/vnd.ms-excel"); header("Content-Disposition:filename=库存记录表.csv"); header('Cache-Control: max-age=0'); $fp = fopen('php://output', 'a'); $head = ['商品编码','商品名称', '商品规格', '可售库存', '占用库存', '换算比例', '换算库存','其他单位']; //定义标题 foreach ($head as $i => $v) { $head[$i] = mb_convert_encoding($v, 'GBK', 'utf-8'); //将中文标题转换编码,否则乱码 } fputcsv($fp, $head); $limit = 10000; $num = 0; //计数器 foreach ($result as $v) { //循环数据 $num++; if ($num == $limit) { ob_flush(); //释放内存 flush(); } $v = parent::formatOrderMan($this->enterpriseId, $v); $rows['materielCode'] = isset($v['materielCode']) ? $v['materielCode'] : ''; //商品编码 $rows['materielName'] = isset($v['materielName']) ? $v['materielName'] : ''; //商品名称 $rows['unitName'] = isset($v['unitName']) ? $v['unitName'] : ''; //商品规格 $rows['inventoryNum'] = isset($v['inventoryNum']) ? $v['inventoryNum'] : ''; //可售库存 $rows['lockInventory'] = isset($v['lockInventory']) ? $v['lockInventory'] : ''; //占用库存 $rows['skuValue'] = $v['isEq'] == 4 ? $v['skuValue'] : ''; //换算比例 $rows['skuNum'] = isset($v['skuNum']) ? $v['skuNum'] : ''; //换算库存 $rows['otherNum'] = isset($v['otherNum']) ? $v['otherNum'] : ''; //其他单位 // $rows['materielName'] = isset($v['materielName']) ? $v['materielName'] : ''; //// $rows['warehouseName'] = isset($v['warehouseName']) ? $v['warehouseName'] : ''; // $rows['unitName'] = isset($v['unitName']) ? $v['unitName'] : ''; //// $rows['skuName'] = isset($v['skuName']) ? $v['skuName'] : ''; // $rows['inventoryNum'] = isset($v['inventoryNum']) ? $v['inventoryNum'] : ''; // $rows['lockInventory'] = isset($v['lockInventory']) ? $v['lockInventory'] : ''; //// $rows['skuValues'] = isset($v['skuValues']) ? $v['skuValues'] : ''; // $rows['skuNums'] = isset($v['skuNums']) ? $v['skuNums'] : ''; // $rows['skuNum'] = isset($v['skuNum']) ? $v['skuNum'] : ''; // $rows['otherNum'] = isset($v['otherNum']) ? $v['otherNum'] : ''; //// $rows['costPrice'] = isset($v['costPrice']) ? $v['costPrice'] : ''; //// $rows['total'] = bcmul($v['inventoryNum'], $v['costPrice'], 4); foreach ($rows as $kk => $vv) { $rs[$kk] = mb_convert_encoding($vv, 'GBK', 'utf-8'); //转译编码 } fputcsv($fp, $rs); $rows = []; } } /** * 库存流水列表 * @param $selectParams * @param $export * @return ResultWrapper * @throws Exception */ public function getInventoryDetailsAll($selectParams, $export) { $limit = $selectParams['limit']; unset($selectParams['limit']); $offset = $selectParams['offset']; unset($selectParams['offset']); self::setDetailsTable($this->enterpriseId, $selectParams['warehouseId']); unset($selectParams['warehouseId']); $dbResult = $this->objDInventoryDetails->select($selectParams, '*', 'id desc', $limit, $offset); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } foreach($dbResult as &$value){ !empty($value['batch']) && $value['batch'] = json_decode($value['batch'], true); $value = $this->formatInventoryDetails($value); } unset($value); $total = $this->objDInventoryDetails->count($selectParams); $formatData = parent::formatOrderMan($this->enterpriseId, $dbResult); $return['data'] = $formatData; $return['total'] = ($total) ? intval($total) : 0; if ($export) { self::exportInventoryDetails($return['data']); exit; } if ($return === false) { return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } else { return ResultWrapper::success($return); } } /** * 格式化流水数据 * @param $value * @return mixed */ public function formatInventoryDetails($value) { //移动加权 $value['costPrice'] = $value['averageCost']; //个别计价 if($value['actionType'] == StatusCode::$standard){ //入库 if($value['costType'] == StatusCode::$costType['sp']){ $batch = json_decode($value['batch'], true); $batchData = array_shift($batch); $value['costPrice'] = isset($batchData['batchCost']) ? $batchData['batchCost'] : 0; } }else{ //出库 if($value['costType'] == StatusCode::$costType['sp']){ $batch = json_decode($value['batch'], true); $total = 0;//出库总价 foreach($batch as $v){ $total = $total + ($v['batchCost'] * $v['num']); } $value['costPrice'] = $total / $value['inventoryNum']; } } return $value; } /** * 流水列表搜索 * @param $params * @param $export * @return ResultWrapper * @throws \Exception */ public function searchAllInventoryDetails($params, $export) { $defaultDSL = ['from' => $params['offset'], 'size' => $params['limit'], 'sort' => ['createTime' => ['order' => 'desc']]]; $selectParams = []; $selectParams[] = ['term' => ['enterpriseId' => $this->enterpriseId]]; !empty($params['warehouseId']) && $selectParams[] = ['term' => ['warehouseId' => $params['warehouseId']]]; !empty($params['operatorId']) && $selectParams[] = ['term' => ['operatorId' => $params['operatorId']]]; !empty($params['skuId']) && $selectParams[] = ['term' => ['skuId' => $params['skuId']]]; (!empty($params['start']) && !empty($params['end'])) && $selectParams[] = ['range' => ['createTime' => ['gte' => $params['start'], 'lte' => $params['end']]]]; !empty($params['search']) && $selectParams[] = ['multi_match' => ['fields' => ['sourceNo', 'materielName', 'batch.batch'], 'query' => $params['search'], "type" => "best_fields", "tie_breaker" => 0.3, "minimum_should_match" => "100%"]]; $dsl = []; !empty($selectParams) && $dsl['query']['bool']['must'][] = $selectParams; $dsl = array_merge($defaultDSL, $dsl); // V(json_encode($dsl,true)); if ($export) { $dbResult = $this->objDInventoryDetails->getScrollSearchQueryDsl($dsl); if (isset($dbResult['error'])) { return ResultWrapper::fail($dbResult, ErrorCode::$dberror); } $returnData = parent::formatEsSelectData($dbResult); self::exportInventoryDetails($returnData['data']); exit; } $dbResult = $this->objDInventoryDetails->getSearchQueryDsl($dsl); if (isset($dbResult['error'])) { return ResultWrapper::fail($dbResult, ErrorCode::$dberror); } $returnData = parent::formatEsSelectData($dbResult, $this->enterpriseId); $objMCommon = new MCommon(); foreach($returnData['data'] as &$value){ $value = $this->formatInventoryDetails($value); $value['sourceName'] = $objMCommon->formatOrderSource($value['source']); } return ResultWrapper::success($returnData); } /** * 库存流水导出方法 * @param $result * @return void * @throws Exception */ public function exportInventoryDetails($result) { //导出到本地 header("Content-type:application/vnd.ms-excel"); header("Content-Disposition:filename=库存流水记录表.csv"); header('Cache-Control: max-age=0'); $fp = fopen('php://output', 'a'); $head = ['单据编号', '制单时间', '单据类型', '商品名称', '出库','入库', '剩余量','其他单位','平均成本', '操作人']; //定义标题 foreach ($head as $i => $v) { $head[$i] = mb_convert_encoding($v, 'GBK', 'utf-8'); //将中文标题转换编码,否则乱码 } fputcsv($fp, $head); $limit = 10000; $num = 0; //计数器 foreach ($result as $value) { //循环数据 $num++; if ($num == $limit) { ob_flush(); //释放内存 flush(); } $v = $this->formatInventoryDetails($value); $v = parent::formatOrderMan($this->enterpriseId, $v); $rows['sourceNo'] = isset($v['sourceNo']) ? $v['sourceNo'] : null; $rows['createTime'] = date('Y-m-d H:i:s', $v['createTime']); $rows['sourceName'] = isset($v['sourceName']) ? $v['sourceName'] : null; $rows['materielName'] = isset($v['materielName']) ? $v['materielName'] : null; $rows['Delivery'] = $v['actionType'] == StatusCode::$standard ? '' : '-' . $v['inventoryNum'];//出库 $rows['Warehousing'] = $v['actionType'] == StatusCode::$standard ? '+' . $v['inventoryNum'] : '';//入库 $rows['inventoryChangeNum'] = isset($v['inventoryChangeNum']) ? $v['inventoryChangeNum'] : null; $rows['otherNum'] = isset($v['otherNum']) ? $v['otherNum'] : null; $rows['costPrice'] = isset($v['costPrice']) ? $v['costPrice'] : null; $rows['operatorName'] = isset($v['operatorName']) ? $v['operatorName'] : null; foreach ($rows as $kk => $vv) { $rs[$kk] = mb_convert_encoding($vv, 'GBK', 'utf-8'); //转译编码 } fputcsv($fp, $rs); $rows = []; } } /** * 库存汇总导出方法 * @param $result * @param $hideAmount * @param $reconciliation * @return void */ public function exportInventoryDetailsStatistics($result, $hideAmount,$reconciliation) { //导出到本地 header("Content-type:application/vnd.ms-excel"); header("Content-Disposition:filename=库存流水记录表.csv"); header('Cache-Control: max-age=0'); $fp = fopen('php://output', 'a'); if($reconciliation){ $head = ['商品名称','商品规格','其他单位','昨日结存总数量','今日入库数量','今日出库总数量','采购入库','采购退货出库','销售出库','销售退货入库','调拨入库','调拨出库','今日结存总数量']; //定义标题 } else { if($hideAmount){ $head = ['商品编码', '商品名称','商品规格','其他单位', '上期结存数量', '本期入库数量', '本期出库数量', '本期结存数量']; //定义标题 } else { $head = ['商品编码', '商品名称','商品规格','其他单位', '上期结存数量', '上期结存金额', '本期入库数量', '本期入库金额', '本期出库数量', '本期出库金额', '本期结存数量', '本期结存金额']; //定义标题 } } foreach ($head as $i => $v) { $head[$i] = mb_convert_encoding($v, 'GBK', 'utf-8'); //将中文标题转换编码,否则乱码 } fputcsv($fp, $head); $limit = 10000; $num = 0;//计数器 foreach ($result as $value) {//循环数据 foreach($value['Details']as $v){ $num++; if ($num == $limit) { ob_flush();//释放内存 flush(); } if($reconciliation){ $rows['materielName'] = isset($value['materielName']) ? $value['materielName'] : null;//商品名称 $rows['skuName'] = isset($v['skuName']) ? $v['skuName'].(!empty($v['skuName']) ? '_' : '').$v['unitName'] : null;//商品规格 $rows['otherNum'] = isset($value['otherNum']) ? $value['otherNum'] : 0;//其他单位 $rows['topEndNum'] = isset($v['topEndNum']) ? $v['topEndNum'] : null;//昨日结存总数量 $rows['selfInNum'] = isset($v['selfInNum']) ? $v['selfInNum'] : null;//今日入库数量 $rows['selfOutNum'] = isset($v['selfOutNum']) ? $v['selfOutNum'] : null;//今日出库总数量 $rows['selfPurchaseInNum'] = isset($v['selfPurchaseInNum']) ? $v['selfPurchaseInNum'] : null;//采购入库 $rows['selfPurchaseReturnOutNum'] = isset($value['selfPurchaseReturnOutNum']) ? $value['selfPurchaseReturnOutNum'] : null;//采购退货出库 $rows['selfSaleOutNum'] = isset($value['selfSaleOutNum']) ? $value['selfSaleOutNum'] : null;//销售出库 $rows['selfSaleReturnInNum'] = isset($v['selfSaleReturnInNum']) ? $v['selfSaleReturnInNum'] : null;//销售退货入库 $rows['selfAllocateInNum'] = isset($v['selfAllocateInNum']) ? $v['selfAllocateInNum'] : null;//调拨入库 $rows['selfAllocateOutNum'] = isset($v['selfAllocateOutNum']) ? $v['selfAllocateOutNum'] : null;//调拨出库 $rows['selfEndNum'] = isset($v['selfEndNum']) ? $v['selfEndNum'] : null;//今日结存总数量 }else{ if($hideAmount){ $rows['materielCode'] = isset($value['materielCode']) ? $value['materielCode'] : null; $rows['materielName'] = isset($value['materielName']) ? $value['materielName'] : null; $rows['skuName'] = isset($v['skuName']) ? $v['skuName'].(!empty($v['skuName']) ? '_' : '').$v['unitName'] : null; $rows['otherNum'] = isset($value['otherNum']) ? $value['otherNum'] : 0;//其他单位 $rows['topEndNum'] = isset($v['topEndNum']) ? $v['topEndNum'] : null; $rows['selfInNum'] = isset($v['selfInNum']) ? $v['selfInNum'] : null; $rows['selfOutNum'] = isset($v['selfOutNum']) ? $v['selfOutNum'] : null; $rows['selfEndNum'] = isset($v['selfEndNum']) ? $v['selfEndNum'] : null; }else{ $rows['materielCode'] = isset($value['materielCode']) ? $value['materielCode'] : null; $rows['materielName'] = isset($value['materielName']) ? $value['materielName'] : null; $rows['skuName'] = isset($v['skuName']) ? $v['skuName'].(!empty($v['skuName']) ? '_' : '').$v['unitName'] : null; $rows['otherNum'] = isset($value['otherNum']) ? $value['otherNum'] : 0;//其他单位 $rows['topEndNum'] = isset($v['topEndNum']) ? $v['topEndNum'] : null; $rows['topEndAmount'] = isset($v['topEndAmount']) ? $v['topEndAmount'] : null; $rows['selfInNum'] = isset($v['selfInNum']) ? $v['selfInNum'] : null; $rows['selfInAmount'] = isset($v['selfInAmount']) ? $v['selfInAmount'] : null; $rows['selfOutNum'] = isset($v['selfOutNum']) ? $v['selfOutNum'] : null; $rows['selfOutAmount'] = isset($v['selfOutAmount']) ? $v['selfOutAmount'] : null; $rows['selfEndNum'] = isset($v['selfEndNum']) ? $v['selfEndNum'] : null; $rows['selfEndAmount'] = isset($v['selfEndAmount']) ? $v['selfEndAmount'] : null; } } foreach ($rows as $kk => $vv) { $rs[$kk] = mb_convert_encoding($vv, 'GBK', 'utf-8'); //转译编码 } fputcsv($fp, $rs); $rows = []; } } } /** * 计算表名 * @param $params * @param string $table * @return ResultWrapper * @throws Exception */ public function setInventoryDetailsTableName($params,$table = 'qianniao_inventory_details') { if(empty($params['warehouseId'])) return ResultWrapper::fail('仓库参数错误', ErrorCode::$paramError); if(empty($params['start'])) return ResultWrapper::fail('开始时间参数错误', ErrorCode::$paramError); if(empty($params['end'])) return ResultWrapper::fail('结束时间参数错误', ErrorCode::$paramError); $table && $table = $table.'_'.$this->enterpriseId.'_'.$params['warehouseId'].'_'; $startTableTerm = self::setDetailsTableTerm($params['start']); $endTableTerm = self::setDetailsTableTerm($params['end']); $startYear = substr(date('Y', $params['start']), -2); $endYear = substr(date('Y', $params['end']), -2); if($startTableTerm == $endTableTerm){//同一个表 $dbResult = $this->objDInventoryDetails->existsTable($table.$startTableTerm); if($dbResult){ return ResultWrapper::success([$table.$startTableTerm]); } return ResultWrapper::success([]); } //不同表 $tableNameArray = []; for($ii = $startYear; $ii <= $endYear; $ii++){ for($i = 1; $i <= 4; $i++){ $term = $ii.$i; if($startTableTerm <= $term && $term <= $endTableTerm){ $tableName = $table.$term; $dbResult = $this->objDInventoryDetails->existsTable($tableName); if($dbResult){//存在 $tableNameArray[] = $tableName; }else{//不存在 continue; } } } } return ResultWrapper::success($tableNameArray); } /** * 库存流水详情列表 * @param $selectParams * @param $export * @param $hideAmount * @return ResultWrapper * @throws \Exception */ public function getAllInventoryDetailsList($selectParams, $export, $hideAmount) { $limit = $selectParams['limit']; unset($selectParams['limit']); $offset = $selectParams['offset']; unset($selectParams['offset']); if(empty($selectParams['start']) && empty($selectParams['end'])){ $selectParams['start'] = 1546272000;//2 019-01-01 00:00:00 $selectParams['end'] = time(); } $start = $selectParams['start']; if($selectParams['start'] > $selectParams['end']){ $selectParams['start'] = $selectParams['end']; $selectParams['end'] = $start; } // 计算分表 $modelResult = self::setInventoryDetailsTableName($selectParams); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $tableNameArray = $modelResult->getData(); if(empty($tableNameArray)){ $return['data'] = []; $return['total'] = 0; return ResultWrapper::success($return); } if ( strstr($selectParams["search"],'RK') or strstr($selectParams["search"],'CK')){ $status = strstr($selectParams["search"],'K',true).'K'; foreach (StatusCode::$noPrefix as $v){ if ($status ==$v){ $selectParams["search"] = substr($selectParams["search"],strlen($status)); break; } } } // 组装查询sql $whereSql = ''; !empty($selectParams['search']) && $whereSql .= ' and materielName like "%'.$selectParams["search"].'%" or sourceNo like "%'.$selectParams["search"].'%"'; !empty($selectParams['skuId']) && $whereSql .= ' and skuId = '.$selectParams["skuId"]; !empty($selectParams['operatorId']) && $whereSql .= ' and operatorId = '.$selectParams["operatorId"]; !empty($selectParams['warehouseId']) && $whereSql .= ' and warehouseId = '.$selectParams["warehouseId"]; !empty($selectParams['merchantId']) && $whereSql .= ' and merchantId = '.$selectParams["merchantId"]; !empty($selectParams['source']) && $whereSql .= ' and source = '.$selectParams["source"]; $sql = ''; // $field = 'materielId,warehouseId,materielCode,materielName,createTime'; $field = '*'; foreach($tableNameArray as $tableName){ !empty($sql) && $sql = $sql.' union all '; $sql = $sql . '(select '.$field.' from '.$tableName.' where createTime between '.$selectParams['start'].' and '.$selectParams['end'].' '.$whereSql.' )'; } // $sql = 'select materielId,warehouseId,materielCode,materielName,createTime from ('.$sql.') as details group by materielId '; $sql = 'select * from ('.$sql.') as details '; $selectSql = $sql.'order by createTime desc limit '.$offset.','.$limit; $dbResult = $this->objDInventoryDetails->query($selectSql); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } if(empty($dbResult)){ $return['data'] = []; $return['total'] = 0; return ResultWrapper::success($return); } // 计算总条数 $countSql = 'select count(materielId) as count from ( '.$sql.' ) as selectDetails'; $totalDbResult = $this->objDInventoryDetails->query($countSql); if($totalDbResult === false){ return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } $total = array_shift($totalDbResult)['count']; // 提取所有物料id $materielIds = array_column($dbResult, 'materielId'); if(empty($materielIds)) return ResultWrapper::fail('物料id获取失败', ErrorCode::$paramError); $sqlDetails = ''; foreach($tableNameArray as $tableName){ !empty($sqlDetails) && $sqlDetails = $sqlDetails.' union all '; $sqlDetails = $sqlDetails . '(select * from '.$tableName.' where createTime between '.$selectParams['start'].' and '.$selectParams['end'].' and materielId in('.implode(',',$materielIds).') order by createTime desc )'; } if ($export) { $dbResult = $this->objDInventoryDetails->exportQuery($sqlDetails); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } $dbResult = self::formatInventoryStatistics($dbResult, true); self::exportInventoryDetailsStatistics($dbResult, $hideAmount); exit; } $return['data'] = self::formatOrderMan($this->enterpriseId, $dbResult); $return['total'] = ($total) ? intval($total) : 0; return ResultWrapper::success($return); } /** * 库存汇总列表 * @param $selectParams * @param $export * @param $hideAmount * @param $reconciliation * @return ResultWrapper * @throws \Exception */ public function inventoryStatistics($selectParams, $export, $hideAmount,$reconciliation) { $limit = $selectParams['limit']; unset($selectParams['limit']); $offset = $selectParams['offset']; unset($selectParams['offset']); if(empty($selectParams['start']) && empty($selectParams['end'])){ $selectParams['start'] = 1546272000;//2019-01-01 00:00:00 $selectParams['end'] = time(); } $start = $selectParams['start']; if($selectParams['start'] > $selectParams['end']){ $selectParams['start'] = $selectParams['end']; $selectParams['end'] = $start; } //计算分表 $modelResult = self::setInventoryDetailsTableName($selectParams); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $tableNameArray = $modelResult->getData(); if(empty($tableNameArray)){ $return['data'] = []; $return['total'] = 0; return ResultWrapper::success($return); } $whereSql = ''; !empty($selectParams['search']) && $whereSql = ' and materielName like "%'.$selectParams["search"].'%"'; !empty($selectParams['merchantId']) && $whereSql = ' and merchantId = '.$selectParams["merchantId"]; !empty($selectParams['materielCode']) && $whereSql = ' and materielCode = "'.$selectParams["materielCode"].'"'; $sql = ''; $field = 'materielId,warehouseId,materielCode,materielName,createTime,merchantId,otherNum'; foreach($tableNameArray as $tableName){ !empty($sql) && $sql = $sql.' union all '; $sql = $sql . '(select '.$field.' from '.$tableName.' where createTime between '.$selectParams['start'].' and '.$selectParams['end'].$whereSql.' )'; } $sql = 'select materielId,warehouseId,materielCode,materielName,createTime,otherNum from ('.$sql.') as details group by materielId '; $selectSql = $sql.'order by createTime desc limit '.$offset.','.$limit; $dbResult = $this->objDInventoryDetails->query($selectSql); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } if(empty($dbResult)){ $return['data'] = []; $return['total'] = 0; return ResultWrapper::success($return); } $countSql = 'select count(materielId) as count from ( '.$sql.' ) as selectDetails'; $totalDbResult = $this->objDInventoryDetails->query($countSql); if($totalDbResult === false){ return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } $total = array_shift($totalDbResult)['count']; $materielIds = array_column($dbResult, 'materielId'); if(empty($materielIds)) return ResultWrapper::fail('物料id获取失败', ErrorCode::$paramError); $sqlDetails = ''; foreach($tableNameArray as $tableName){ !empty($sqlDetails) && $sqlDetails = $sqlDetails.' union all '; $sqlDetails = $sqlDetails . '(select * from '.$tableName.' where createTime between '.$selectParams['start'].' and '.$selectParams['end'].' and materielId in('.implode(',',$materielIds).') order by createTime desc )'; } if ($export) { $dbResult = $this->objDInventoryDetails->exportQuery($sqlDetails); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } $dbResult = self::formatInventoryStatistics($dbResult, true); self::exportInventoryDetailsStatistics($dbResult, $hideAmount,$reconciliation); exit; } $midDbResult = $this->objDInventoryDetails->query($sqlDetails); if($midDbResult === false){ return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$paramError); } $formatData = self::formatInventoryStatistics($midDbResult, true); $return['data'] = parent::formatOrderMan($this->enterpriseId,$formatData); $return['total'] = ($total) ? intval($total) : 0; return ResultWrapper::success($return); } /** * 库存汇总搜索 * @param $params * @param $export * @param $hideAmount * @return ResultWrapper * @throws \Exception */ public function searchInventoryStatistics($params, $export, $hideAmount) { $defaultDSL = ['from' => $params['offset'], 'size' => $params['limit'], 'sort' => ['id' => ['order' => 'desc']]]; $selectParams = []; $selectParams[] = ['term' => ['enterpriseId' => $this->enterpriseId]]; !empty($params['warehouseId']) && $selectParams[] = ['term' => ['warehouseId' => $params['warehouseId']]]; (!empty($params['start']) && !empty($params['end'])) && $selectParams[] = ['range' => ['createTime' => ['gte' => $params['start'], 'lte' => $params['end']]]]; !empty($params['search']) && $selectParams[] = ['multi_match' => ['fields' => ['materielName', 'materielCode'], 'query' => $params['search'], "type" => "best_fields", "tie_breaker" => 0.3, "minimum_should_match" => "50%"]]; $dsl = []; !empty($selectParams) && $dsl['query']['bool']['must'][] = $selectParams; $dsl = array_merge($defaultDSL, $dsl); if ($export) { $dbResult = $this->objDInventoryDetails->getScrollSearchQueryDsl($dsl); if (isset($dbResult['error'])) { return ResultWrapper::fail($dbResult, ErrorCode::$dberror); } $returnData = parent::formatEsSelectData($dbResult); $returnData['data'] = self::formatInventoryStatistics($returnData['data'], true); self::exportInventoryDetailsStatistics($returnData['data'], $hideAmount); exit; } $dbResult = $this->objDInventoryDetails->getSearchQueryDsl($dsl); if (isset($dbResult['error'])) { return ResultWrapper::fail($dbResult, ErrorCode::$dberror); } $returnData = parent::formatEsSelectData($dbResult, $this->enterpriseId); $returnData['data'] = self::formatInventoryStatistics($returnData['data'], true); return ResultWrapper::success($returnData); } /** * 处理库存汇总数据 * @param $params * @param bool $merge * @return array * @throws \Exception */ public function formatInventoryStatistics($params, $merge = false) { if(empty($params)) return []; $skuIds = array_column(array_values($params), 'skuId'); $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId); $modelResult = $objMSku->getConversion($skuIds); $skuData = []; if ($modelResult->isSuccess()) { $skuData = $modelResult->getData(); } unset($modelResult); //循环流水数据 $returnData = []; foreach($params as $value){ //分组流水数据 if(isset($returnData[$value['materielId']]) && isset($returnData[$value['materielId']]['Details']) && isset($returnData[$value['materielId']]['Details'][$value['skuId']])){ $data = $returnData[$value['materielId']]['Details'][$value['skuId']]; //上期结存 if($data['smallCreateTime'] > $value['createTime']){ if($value['actionType'] == StatusCode::$standard){ //入库 $data['topEndNum'] = floatval((bcsub($value['inventoryChangeNum'], $value['inventoryNum'], 8))); }else{ //出库 $data['topEndNum'] = floatval(bcadd($value['inventoryNum'], $value['inventoryChangeNum'], 8)); } $data['topEndAmount'] = floatval(bcmul($data['topEndNum'], $value['averageCost'], 4)); $data['smallCreateTime'] = $value['createTime']; } //本期入库 if($value['actionType'] == StatusCode::$standard){ $data['selfInNum'] = floatval(bcadd($data['selfInNum'], $value['inventoryNum'], 8)); $data['selfInAmount'] = floatval(bcadd($data['selfInAmount'], bcmul($value['inventoryNum'], $value['averageCost'], 4), 4)); switch ($value['source']){ case StatusCode::$orderType['purchaseIn']: //采购入库 $data['selfPurchaseInNum'] = floatval(bcadd($data['selfPurchaseInNum'], $value['inventoryNum'], 8)); break; case StatusCode::$orderType['allocateIn']: //调拨入库 $data['selfAllocateInNum'] = floatval(bcadd($data['selfPurchaseInNum'], $value['inventoryNum'], 8)); break; case StatusCode::$orderType['saleReturnIn']: //销售退货入库 $data['selfSaleReturnInNum'] = floatval(bcadd($data['selfSaleReturnInNum'], $value['inventoryNum'], 8)); break; default: break; } }else{ $data['selfOutNum'] = floatval(bcadd($data['selfOutNum'], $value['inventoryNum'], 8)); $data['selfOutAmount'] = floatval(bcadd($data['selfOutAmount'], bcmul($value['inventoryNum'], $value['averageCost'], 4), 4)); switch ($value['source']){ case StatusCode::$orderType['saleOut']: //销售出库 $data['selfSaleOutNum'] = floatval(bcadd($data['selfSaleOutNum'], $value['inventoryNum'], 8)); break; case StatusCode::$orderType['allocateOut']: //调拨出库 $data['selfAllocateOutNum'] = floatval(bcadd($data['selfAllocateOutNum'], $value['inventoryNum'], 8)); break; case StatusCode::$orderType['purchaseReturnOut']: //采购退货出库 $data['selfPurchaseReturnOutNum'] = floatval(bcadd($data['selfPurchaseReturnOutNum'], $value['inventoryNum'], 8)); break; default: break; } } //本期结存 if($data['bigCreateTime'] < $value['createTime']){ $data['selfEndNum'] = floatval($value['inventoryChangeNum']); $data['selfEndAmount'] = floatval(bcmul($value['inventoryChangeNum'], $value['averageCost'], 4)); $data['bigCreateTime'] = $value['createTime']; } $returnData[$value['materielId']]['Details'][$value['skuId']] = $data; }else{ $data = [ 'bigCreateTime' => $value['createTime'], 'smallCreateTime' => $value['createTime'], 'warehouseId' => $value['warehouseId'], 'materielId' => $value['materielId'], 'skuId' => isset($skuData[$value['skuId']]['masterSkuId']) ? $skuData[$value['skuId']]['masterSkuId'] : $value['skuId'], 'materielCode' => isset($value['materielCode']) ? $value['materielCode'] : createCode(StatusCode::$code['goodsBasic']['prefix'], $value['materielId'], StatusCode::$code['goodsBasic']['length']), 'materielName' => $value['materielName'], ]; //上期结存 本期第一个出/入数量 +/- 变动后数量 = 上期结存数量 if($value['actionType'] == StatusCode::$standard){ //入库 $data['topEndNum'] = floatval(bcsub($value['inventoryChangeNum'], $value['inventoryNum'], 8)); }else{ //出库 $data['topEndNum'] = floatval(bcadd($value['inventoryNum'], $value['inventoryChangeNum'], 8)); } $data['topEndAmount'] = floatval(bcmul($data['topEndNum'], $value['averageCost'], 4)); //本期入库 $data['selfInNum'] = 0; $data['selfInAmount'] = 0; //本期出库 $data['selfOutNum'] = 0; $data['selfOutAmount'] = 0; $data['selfPurchaseInNum'] = 0; $data['selfAllocateInNum'] = 0; $data['selfSaleReturnInNum'] = 0; $data['selfSaleOutNum'] = 0; $data['selfAllocateOutNum'] = 0; $data['selfPurchaseReturnOutNum'] = 0; if($value['actionType'] == StatusCode::$standard){ $data['selfInNum'] = floatval($value['inventoryNum']); $data['selfInAmount'] = floatval(bcmul($value['inventoryNum'], $value['averageCost'], 4)); switch ($value['source']){ case StatusCode::$orderType['purchaseIn']: //采购入库 $data['selfPurchaseInNum'] = floatval($value['inventoryNum']); break; case StatusCode::$orderType['allocateIn']: //调拨入库 $data['selfAllocateInNum'] = floatval($value['inventoryNum']); break; case StatusCode::$orderType['saleReturnIn']: //销售退货入库 $data['selfSaleReturnInNum'] = floatval($value['inventoryNum']); break; default: break; } }else{ $data['selfOutNum'] = floatval($value['inventoryNum']); $data['selfOutAmount'] = floatval(bcmul($value['inventoryNum'], $value['averageCost'], 4)); switch ($value['source']){ case StatusCode::$orderType['saleOut']: //销售出库 $data['selfSaleOutNum'] = floatval($value['inventoryNum']); break; case StatusCode::$orderType['allocateOut']: //调拨出库 $data['selfAllocateOutNum'] = floatval($value['inventoryNum']); break; case StatusCode::$orderType['purchaseReturnOut']: //采购退货出库 $data['selfPurchaseReturnOutNum'] = floatval($value['inventoryNum']); break; default: break; } } //本期结存 $data['selfEndNum'] = floatval($value['inventoryChangeNum']); $data['selfEndAmount'] = floatval(bcmul($value['inventoryChangeNum'], $value['averageCost'], 4)); if(!isset($returnData[$value['materielId']])){ $returnData[$value['materielId']]['warehouseId'] = $value['warehouseId']; $returnData[$value['materielId']]['materielId'] = $value['materielId']; $returnData[$value['materielId']]['materielCode'] = $value['materielCode']; $returnData[$value['materielId']]['materielName'] = $value['materielName']; } $returnData[$value['materielId']]['Details'][$value['skuId']] = parent::formatSkuId($this->enterpriseId,$data); } } foreach($returnData as &$value){ $value['Details'] = array_merge($value['Details']); } if($merge) return array_merge($returnData); return $returnData; } /** * 批次列表 * @param $selectParams * @return ResultWrapper * @throws Exception */ public function getAllBatch($selectParams) { $limit = $selectParams['limit']; unset($selectParams['limit']); $offset = $selectParams['offset']; unset($selectParams['offset']); self::setBatchTable($this->enterpriseId, $selectParams['warehouseId']); $where = ' warehouseId ='.$selectParams['warehouseId']; // 关键字筛选 if( isset($selectParams['keyword']) && !empty($selectParams['keyword']) ){ // 根据输入的商品名称关键字查询对应的商品ids $objMGoodsBasic = new MGoodsBasic($this->onLineUserCenterId, $this->enterpriseId); $materielIdS = $objMGoodsBasic->getBasicGoodsIdsByGoodsTitleKeyword($selectParams['keyword']); if(!$materielIdS->isSuccess()){ return ResultWrapper::fail($materielIdS->getData(), $materielIdS->getErrorCode()); } $materielIdS = $materielIdS->getData(); unset($selectParams['keyword']); if( empty($materielIdS) ){ return ResultWrapper::success(['data'=>[],'total'=>0]); } if (empty($selectParams['batchNo'])){ $where .=' and materielId in ('.implode(',', $materielIdS).')'; } } //批次号 if( isset($selectParams['batchNo']) && !empty($selectParams['batchNo']) ){ $where .= ' and batchNo ='.$selectParams['batchNo']; } // 时间筛选 if( isset($selectParams['startTime']) && !empty($selectParams['startTime']) && isset($selectParams['endTime']) && !empty($selectParams['endTime'])){ $where .=' and createTime >= '.$selectParams['startTime'].' and createTime <= '.$selectParams['endTime']; } // materielId过滤 if( isset($selectParams['materielId']) && !empty($selectParams['materielId']) ){ $where .= ' and materielId ='.$selectParams['materielId']; } // skuId过滤 if( isset($selectParams['skuId']) && !empty($selectParams['skuId']) ){ $where .= ' and skuId ='.$selectParams['skuId']; } $dbResult = $this->objDInventoryBatch->select($where, '*', 'id asc', $limit, $offset); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } $total = $this->objDInventoryBatch->count($where); $formatData = parent::formatOrderMan($this->enterpriseId, $dbResult); $return['data'] = $formatData; $return['total'] = ($total) ? intval($total) : 0; if ($return === false) { return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } else { return ResultWrapper::success($return); } } /** * 批次搜索 * @param $params * @return ResultWrapper * @throws Exception */ public function searchAllInventoryBatch($params) { $defaultDSL = ['from' => $params['offset'], 'size' => $params['limit'], 'sort' => ['createTime' => ['order' => 'desc']]]; $selectParams = []; $selectParams[] = ['term' => ['enterpriseId' => $this->enterpriseId]]; !empty($params['warehouseId']) && $selectParams[] = ['term' => ['warehouseId' => $params['warehouseId']]]; (!empty($params['start']) && !empty($params['end'])) && $selectParams[] = ['range' => ['createTime' => ['gte' => $params['start'], 'lte' => $params['end']]]]; !empty($params['search']) && $selectParams[] = ['multi_match' => ['fields' => ['batchNo', 'originNo', 'materielName'], 'query' => $params['search'], 'fuzziness' => 'AUTO']]; $dsl = []; !empty($selectParams) && $dsl['query']['bool']['must'][] = $selectParams; $dsl = array_merge($defaultDSL, $dsl); $dbResult = $this->objDInventoryBatch->getSearchQueryDsl($dsl); if (isset($dbResult['error'])) { return ResultWrapper::fail($dbResult, ErrorCode::$dberror); } $returnData = parent::formatEsSelectData($dbResult, $this->enterpriseId); return ResultWrapper::success($returnData); } /** * 批次详情 * @param $selectParams * @return ResultWrapper * @throws Exception */ public function getBatchInfo($selectParams) { $skuIds = [ 871,870,868,865,872,869 ]; self::getInventoryBySkuIds($skuIds); $this->objDInventoryBatch->setTable('qianniao_inventory_batch_'.$this->enterpriseId.'_'.$selectParams['warehouseId']); $dbResult = $this->objDInventoryBatch->get($selectParams); if($dbResult === false){ return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } $returnData = parent::formatOrderMan($this->enterpriseId, $dbResult); return ResultWrapper::success($returnData); } /** * 库存不足自动预警 * @param $data * @return ResultWrapper */ public function inventoryNullMessage($data) { //获取当前设置的预警数量 $objMBasicSetup = new MBasicSetup($this->enterpriseId); $modelResult = $objMBasicSetup->getBasicSetup(); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $system = $modelResult->getData(); if(!isset($system['basicData']) || !isset($system['basicData']['goodsNum']) || empty((int)$system['basicData']['goodsNum'])){ return ResultWrapper::success(true); } $settingNum = $system['basicData']['goodsNum']; unset($modelResult); $insertMessage = []; foreach($data as $value){ //判断剩余数量是否低于预警数量 if(bccomp($settingNum, $value['inventoryChangeNum'])){ //如果低于等于预警数量 //创建一条预警消息发送给当前企业管理员 $insertMessage[] = $value['materielName']; } } $params = [ 'enterpriseId' => $this->enterpriseId, 'data' => $insertMessage, ]; if($insertMessage){ self::inventoryNumWarning($params, 'MMessage'); } } /** * 库存为空自动下架 * 根据商铺id和物料id * @param $params * @param array $updateData * @return ResultWrapper * @throws Exception */ public function inventoryNullSetGoodsDown($params, $updateData = []) { if (empty($params)) return ResultWrapper::fail('参数为空', ErrorCode::$paramError); //查询系统设置 $objMBasicSetup = new MBasicSetup($this->enterpriseId); $modelResult = $objMBasicSetup->getBasicSetup(); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $system = $modelResult->getData(); //判断是否开启 库存为空 下架商品功能 if(isset($system['basicData']) || isset($system['basicData']['autoRemoveGoods']) || $system['basicData']['autoRemoveGoods'] == StatusCode::$standard){ return ResultWrapper::success(true); } //判断是否是全部库存为0 TODO $whereParams = []; foreach ($params as $value) { $whereParams[$value['shopId']][] = $value['materielId']; } $objMGoods = new MGoods($this->enterpriseId, false, $this->onLineUserCenterId); foreach ($whereParams as $shopId => $materielIds) { if (empty($updateData)) { $updateData = [ 'enableStatus' => StatusCode::$delete, ]; } $updateData['updateTime'] = time(); $where = ['shopId' => $shopId, 'basicGoodsId' => $materielIds]; $modelResult = $objMGoods->updateGoodsData($updateData, $where); if (!$modelResult->isSuccess()) { return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } } return ResultWrapper::success(true); } /** * 根据仓库id查询所有物料库存信息 * @param $selectParams * @return ResultWrapper * @throws Exception * $export 导出 */ public function getInventoryByWarehouseId($selectParams,$export = 0) { $limit = $selectParams['limit']; unset($selectParams['limit']); $offset = $selectParams['offset']; unset($selectParams['offset']); if($export){ $limit = null; $offset = null; } $categoryId = isset($selectParams['categoryId']) ? $selectParams['categoryId'] : ''; unset($selectParams['categoryId']); if(isset($selectParams['search']) || !empty($categoryId)){ $objDGoodsBasic = new DGoodsBasic('default'); $objDGoodsBasic->setTable( 'qianniao_goods_basic_' . $this->enterpriseId); $sql = 'select id from '.$objDGoodsBasic->get_Table().' WHERE deleteStatus = '.StatusCode::$standard; if (isset($selectParams['search']) && !empty($selectParams['search'])){ $search = '"%'.$selectParams['search'].'%"'; $sql .= ' AND ( title LIKE '.$search.' OR code LIKE '.$search.') '; } if (!empty($categoryId)){ $sql .= ' AND find_in_set('.$categoryId.',categoryPath) '; } $dbResult = $objDGoodsBasic->query($sql); if ($dbResult === false) { return ResultWrapper::fail($objDGoodsBasic->error(), ErrorCode::$dberror); } $selectParams['materielId'] = []; foreach ($dbResult as $value) { $selectParams['materielId'][] = $value['id']; } unset($selectParams['search']); if (empty($selectParams['materielId'])) { $return['data'] = []; $return['total'] = 0; return ResultWrapper::success($return); } } $dbResult = $this->objDInventoryWarehouse->select($selectParams, '*,inventoryNum as allNum, inventoryNum * costPrice as total', 'createTime desc', $limit, $offset); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } if (empty($dbResult)) { $return['data'] = []; $return['total'] = 0; return ResultWrapper::success($return); } $total = $this->objDInventoryWarehouse->count($selectParams); if ($total === false) { return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } $formatData = parent::formatOrderMan($this->enterpriseId, $dbResult); $return['data'] = $formatData; $return['total'] = ($total) ? intval($total) : 0; //仓库库存导出 if($export){ self::exportInventoryWarehouse($formatData); exit; } return ResultWrapper::success($return); } /** * 根据仓库id和物料ids查询物料批次信息和剩余可用库存 * @param $params * @param bool $fields * @return ResultWrapper * @throws Exception */ public function getBatchByIds($params, $fields = false) { $materielIds = []; foreach ($params as $value) { $materielIds[$value['warehouseId']][] = $value['materielId']; } $formatBatch = []; foreach ($materielIds as $warehouseId => $materielId) { self::setBatchTable($this->enterpriseId, $warehouseId, 'qianniao_inventory_batch'); $where = ' materielId in(' . implode(',', $materielId) . ') and warehouseId = ' . $warehouseId . ' and num > 0 '; $order = ' createTime asc'; if ($fields) { $fields .= ',warehouseId,materielId'; } else { $fields = '*'; } $dbResult = $this->objDInventoryBatch->select($where, $fields, $order); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } foreach ($dbResult as $value) { $mdKey = md5($value['warehouseId'] . $value['materielId']); if ($fields) { unset($value['warehouseId']); unset($value['materielId']); } $formatBatch[$mdKey][] = $value; } } foreach ($params as &$value) { $value['batch'] = $formatBatch[md5($value['warehouseId'] . $value['materielId'])]; } unset($value); return ResultWrapper::success($params); } /** * 计算物料出那些批次 * @param $params * @param bool $type * @return ResultWrapper * @throws Exception */ public function getBatchByInventoryOut($params, $type = false) { $modelResult = self::getBatchByIds($params, 'batchNo, num'); if (!$modelResult->isSuccess()) { return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $batchData = $modelResult->getData(); unset($modelResult); $returnData = []; foreach ($batchData as &$value) { $num = $value['num'];//要出的物料数量 foreach ($value['batch'] as $batch) { if ($num <= $batch['num']) {//批次剩余库存数量够 $value['batchData'][] = [ 'batchNo' => $batch['batchNo'], 'lessNum' => $num, ]; break; } $num = bcsub($num,$batch['num']); $value['batchData'][] = [ 'batchNo' => $batch['batchNo'], 'lessNum' => $num, ]; } $returnData[md5($value['warehouseId'] . $value['materielId'])] = $value['batchData']; } if ($type) { return ResultWrapper::success($returnData); } return ResultWrapper::success($batchData); } /** * 统计商品的种类 * @return int|ResultWrapper */ public function statistics() { //库存商品总 $numberOfProductsInStock = $this->objOverviewCache->getAggregateStatistics($this->enterpriseId, 'numberOfProductsInStock'); if (!$numberOfProductsInStock) { $sql = 'SELECT COUNT(id) FROM ' . $this->objDInventory->get_Table() . ' WHERE inventoryNum > 0 GROUP BY materielId,skuId'; $dbResult = $this->objDInventory->query($sql); if ($dbResult === false) { return ResultWrapper::fail('操作数据库失败', ErrorCode::$dberror); } $num = count($dbResult); $this->objOverviewCache->setAggregateStatistics($this->enterpriseId, 'numberOfProductsInStock', $num); unset($sql); unset($dbResult); $return['numberOfProductsInStock'] = $num; } else { $return['numberOfProductsInStock'] = $numberOfProductsInStock; } //库存总金额 $totalMoneyOfInventory = $this->objOverviewCache->getAggregateStatistics($this->enterpriseId, 'totalMoneyOfInventory'); if (!$totalMoneyOfInventory) { $sql = "select sum(costPrice) as amount from " . $this->objDInventory->get_Table(); $dbResult = $this->objDInventory->query($sql); if ($dbResult === false) { return ResultWrapper::fail('操作数据库失败', ErrorCode::$dberror); } $amount = isset($dbResult[0]['amount']) ? $dbResult[0]['amount'] : 0; $this->objOverviewCache->setAggregateStatistics($this->enterpriseId, 'totalMoneyOfInventory', $amount); $return['totalMoneyOfInventory'] = $amount; }else{ $return['totalMoneyOfInventory'] = $totalMoneyOfInventory; } return $return; } /** * 根据源头id获取批次信息和库存剩余数量 * @param $params * @return ResultWrapper */ public function getBatchDataByOriginId($warehouseId, $originId, $skuIds) { if(empty($warehouseId)) return ResultWrapper::fail('查询批次warehouseId参数错误', ErrorCode::$paramError); if(empty($originId)) return ResultWrapper::fail('查询批次originId参数错误', ErrorCode::$paramError); if(empty($skuIds)) return ResultWrapper::fail('查询批次skuIds参数错误', ErrorCode::$paramError); //转换单位 $objMSku = new MSku($this->onLineUserCenterId, $this->enterpriseId); $modelResult = $objMSku->getConversion($skuIds); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } $skuData = $modelResult->getData(); unset($modelResult); $masterSkuIds = array_column($skuData, 'masterSkuId'); //查询批次 self::setBatchTable($this->enterpriseId,$warehouseId, 'qianniao_inventory_batch'); $dbResult = $this->objDInventoryBatch->select(['originId' => $originId, 'skuId' => $masterSkuIds]); if ($dbResult === false) { return ResultWrapper::fail($this->objDInventoryBatch->error(), ErrorCode::$dberror); } $batchResult = $dbResult; unset($dbResult); if(empty($batchResult)){ return ResultWrapper::fail('批次数据为空', ErrorCode::$paramError); } $batchData = []; foreach($batchResult as $value){ if(isset($batchData[$value['skuId']])){ $batchData[$value['skuId']]['num'] = bcadd($batchData[$value['skuId']]['num'], $value['num'], 8); }else{ $batchData[$value['skuId']] = $value; } } //转换数量 $inventoryData = []; foreach($skuData as $key => $value){ $inventoryNum = $batchData[$value['masterSkuId']]['num']; if($inventoryNum > 0){ if($value['isMaster'] == StatusCode::$standard){ $inventoryData[$key]['num'] = $inventoryNum; }else{ if($value['isNew'] == StatusCode::$standard){ $inventoryData[$key]['num'] = bcdiv($inventoryNum, $value['conversion'], 8); }else{ $inventoryData[$key]['num'] = bcmul($inventoryNum, $value['conversion'], 8); } } }else{ $inventoryData[$key]['num'] = 0; } } return ResultWrapper::success($inventoryData); } /** * 增加详情es数据 * @param $data * @param $ids * @return ResultWrapper */ /* public function addEsData($data, $ids) { foreach ($data as $key => $value) { $modelResult = self::updateEsData($value, $ids[$key]); if (!$modelResult->isSuccess()) { return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } } return ResultWrapper::success(true); }*/ /** * 添加详情es * @param $id * @param $data * @return ResultWrapper */ /*public function updateEsData($data, $id) { $addEsData = [ 'id' => $id, 'enterpriseId' => $this->enterpriseId, 'sourceNo' => StatusCode::$noPrefix[$data['source']].$data['sourceNo'], 'warehouseId' => $data['warehouseId'], 'materielId' => $data['materielId'], 'materielName' => $data['materielName'], 'operatorId' => $data['operatorId'], 'operatorName' => $data['operatorName'], 'inventoryNum' => $data['inventoryNum'], 'inventoryChangeNum' => $data['inventoryChangeNum'], 'skuId' => $data['skuId'], 'unitName' => $data['unitName'], 'skuName' => $data['skuName'], 'source' => $data['source'], 'batch' => json_decode($data['batch'], true), 'costType' => $data['costType'], 'averageCost' => $data['averageCost'], 'actionType' => $data['actionType'], 'createTime' => $data['createTime'], 'updateTime' => $data['updateTime'], ]; //创建es id $esId = self::esId($id); $result = $this->objDInventoryDetails->addUpSearchIndexDocument($addEsData, $esId); // var_dump($result); if (isset($result['_shards']) && isset($result['_shards']['successful']) && $result['_shards']['successful'] == 1) { return ResultWrapper::success(isset($result['_id']) ? $result['_id'] : false); } return ResultWrapper::fail($result['error']['reason'], ErrorCode::$paramError); // return ResultWrapper::fail('ES添加失败', ErrorCode::$paramError); }*/ /** * 拼接详情es id * @param $id * @return string */ /*public function esId($id) { return 'EnterpriseId_' . $this->enterpriseId . '_inventoryDetailsId_' . $id; }*/ /** * 格式化入库es */ public function formatInventoryDetailsEsData() { //查询列表数据 $dbResult = $this->objDInventoryDetails->select([],'*'); if($dbResult === false){ return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } if(empty($dbResult)){ return ResultWrapper::fail('格式化数据为空', ErrorCode::$dberror); } //增加es搜索 foreach($dbResult as $value){ //增加es搜索 $modelResult = self::updateEsData($value, $value['id']); if(!$modelResult->isSuccess()){ return ResultWrapper::fail($modelResult->getData(), $modelResult->getErrorCode()); } } return ResultWrapper::success('格式化成功'); } public function __destruct() { // TODO: Implement __destruct() method. if ($this->updateCache === false) return true; //统计库存商品数 $sql = 'SELECT COUNT(id) FROM ' . $this->objDInventory->get_Table() . ' WHERE inventoryNum > 0 GROUP BY materielId,skuId'; $dbResult = $this->objDInventory->query($sql); if ($dbResult === false) { return false; } $num = count((array)$dbResult); $this->objOverviewCache->setAggregateStatistics($this->enterpriseId, 'numberOfProductsInStock', $num); //库存总金额 $sql = "select sum((inventoryNum + lockInventory)*costPrice) as amount from " . $this->objDInventory->get_Table(); $dbResult = $this->objDInventory->query($sql); if ($dbResult === false) { return false; } $amount = isset($dbResult[0]['amount']) ? $dbResult[0]['amount'] : 0; $this->objOverviewCache->setAggregateStatistics($this->enterpriseId, 'totalMoneyOfInventory', $amount); return true; } /** * 修改负库存出库流水成本 */ public function updateSaleOrderOutCostPrise($warehouseId, $skuIds, $skuCostParse) { //计算表名 self::setDetailsTable($this->enterpriseId, $warehouseId); $where = [ 'skuId' => $skuIds, 'actionType' => 4, 'source' => StatusCode::$orderType['saleOut'] ]; //查询所有包含skuId的订单出库库存流水 $dbResult = $this->objDInventoryDetails->select($where); if($dbResult === false){ return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } $return = []; if(empty($dbResult)){ return ResultWrapper::success($return); } //拿到所有订单id $orderId = []; $updateOrder = []; $beginStatus = $this->objDInventoryDetails->beginTransaction(); foreach($dbResult as $value){ !in_array($value['originId'],$orderId) && $orderId[] = $value['originId']; if(isset($skuCostParse[$value['skuId']])){ $updateOrder[] = [ 'where' => [ 'orderId' => $value['originId'], 'skuId' => $value['skuId'], ], 'update' => [ 'outCostPrice' => $skuCostParse[$value['skuId']] ] ]; //修改流水记录的出库成本 $result = $this->objDInventoryDetails->update(['averageCost' => $skuCostParse[$value['skuId']]], ['id' => $value['id']]); if($result === false){ $this->objDInventoryDetails->rollBack(); return ResultWrapper::fail($this->objDInventoryDetails->error(), ErrorCode::$dberror); } } } $beginStatus && $this->objDInventoryDetails->commit(); $return['orderId'] = $orderId; $return['updateOrder'] = $updateOrder; return ResultWrapper::success($return); } /** * 修改库存成本 * @param $params * @return ResultWrapper */ public function updateInventoryCost($params) { $where = [ 'skuId' => $params['skuId'], ]; $sql = ' skuId = '.$params['skuId'].' and merchantId <> 0'; $dbResult = $this->objDInventoryWarehouse->get($sql); if($dbResult === false){ return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } if(empty($dbResult)){ return ResultWrapper::success(false); } //修改库存成本 $update = [ 'skuId' => $params['skuId'], 'costPrice' => $params['costPrice'], 'updateTime' => time() ]; $beginStatus = $this->objDInventoryWarehouse->beginTransaction(); $dbResult = $this->objDInventoryWarehouse->update($update,$where); if($dbResult === false){ $this->objDInventoryWarehouse->rollBack(); return ResultWrapper::fail($this->objDInventoryWarehouse->error(), ErrorCode::$dberror); } $beginStatus && $this->objDInventoryWarehouse->commit(); return ResultWrapper::success($dbResult); } /** * 仓库库存导出方法 * @param $result * @return void * @throws Exception */ public function exportInventoryWarehouse($result) { //导出到本地 header("Content-type:application/vnd.ms-excel"); header("Content-Disposition:filename=仓库库存记录表.csv"); header('Cache-Control: max-age=0'); $fp = fopen('php://output', 'a'); $head = ['物料编码', '商品', '规格', '仓库库存', '换算比例','换算库存']; //定义标题 foreach ($head as $i => $v) { $head[$i] = mb_convert_encoding($v, 'GBK', 'utf-8'); //将中文标题转换编码,否则乱码 } fputcsv($fp, $head); $limit = 10000; $num = 0; //计数器 foreach ($result as $v) { //循环数据 $num++; if ($num == $limit) { ob_flush(); //释放内存 flush(); } $rows['materielCode'] = isset($v['materielCode']) ? $v['materielCode'] : '';//物料编码 $rows['warehouseName'] = isset($v['materielName']) ? $v['materielName'] : '';//商品 $rows['unitName'] = isset($v['unitName']) ? $v['unitName'] : '';//规格 $rows['inventoryNum'] = isset($v['inventoryNum']) ? $v['inventoryNum'] : '';//仓库库存 $rows['skuValue'] = isset($v['skuValue']) ? $v['skuValue'] : '';//换算比例 $rows['otherNum'] = isset($v['otherNum']) ? $v['otherNum'] : '';//换算库存 foreach ($rows as $kk => $vv) { $rs[$kk] = mb_convert_encoding($vv, 'GBK', 'utf-8'); //转译编码 } fputcsv($fp, $rs); $rows = []; } } }