updateData([ 'id' => is_array($param['inventory_goods_id']) ? ['in', $param['inventory_goods_id']] : $param['inventory_goods_id'], 'inventory_order_id' => $param['order_id'] ], [ 'state' => 2 ]); $SerialClass->deleteData([ 'outside_id' => is_array($param['inventory_goods_id']) ? ['in', $param['inventory_goods_id']] : $param['inventory_goods_id'], ]); return callBack(statusCode()['success'], "删除成功"); } catch (\Exception $e) { return callBack(statusCode()['error'], "删除失败"); } } /** * 商户与门店实时盘点 * @param $param * [ * operator_type 1后台端 2收银端 3助手端 * user_type 3商户 4门店 6收银员 * merchant_id * store_id * operator_id 操作人id * supplier_type 1普通供货商 2寄售供货商 * order_id 盘点单id * goodsList 商品信息 * submit_type 1盘点 2保存草稿箱 3实时盘点 * remarks 备注 * ] * @return mixed */ public function storeReal($param) { $verifyResult = $this->goodsVerify($param); //参数验证 if ($verifyResult['status'] != 1) { return $verifyResult; } $param['warehouse_id'] = $verifyResult['data']['warehouse_id']; //销售仓id try { if (!empty($param['order_id'])) { //查询盘点单 $orderResult = $this->searchOrderNumber([ 'user_type' => $param['user_type'], 'order_id' => $param['order_id'] ]); if ($orderResult['status'] != 1) { return $orderResult; } $order_id = $param['order_id']; $order_number = $orderResult['data']; } else { //创建订单 $orderResult = $this->createOrder([ 'user_type' => $param['user_type'], 'merchant_id' => $param['merchant_id'], 'store_id' => $param['store_id'], 'warehouse_id' => $param['warehouse_id'], 'remarks' => $param['remarks'], 'operator_id' => $param['operator_id'], ]); if ($orderResult['status'] != 1) { return $orderResult; } $order_id = $orderResult['data']; $order_number = "SP" . orderNumber($order_id); //订单号 } $param['order_id'] = $order_id; $param['order_number'] = $order_number; if (C('IS_SET_REDIS')) { $this->addLock($param); } $recordResult = $this->inventorySubmit($param); //保存盘点商品记录 if ($recordResult['status'] != 1) { $this->eliminate($param); return $recordResult; } $warehousing_arr = $recordResult['data']['warehousing_arr']; //入库的商品 $stock_arr = $recordResult['data']['stock_arr']; //出库的商品 $moneyTotal = $recordResult['data']['moneyTotal']; //盈亏金额 $numTotal = $recordResult['data']['numTotal']; //盈亏数量 $record_id_arr = $recordResult['data']['record_id_arr']; //新增的记录信息 if (!empty($warehousing_arr)) { //盘盈 $param['warehousing_arr'] = $warehousing_arr; $moreResult = $this->inventoryMore($param); if ($moreResult['status'] != 1) { $this->eliminate($param); return $moreResult; } } if (!empty($stock_arr)) { $param['stock_arr'] = $stock_arr; $lossResult = $this->inventoryLess($param); if ($lossResult['status'] != 1) { $this->eliminate($param); return $lossResult; } } $text = [ 'amount' => $moneyTotal, 'quantity' => $numTotal, 'goods_species' => count($param['goodsList']), 'status' => $param['submit_type'] == 1 ? $param['submit_type'] : 2, 'order_number' => $order_number ]; switch ($param['user_type']) { case 3: //商户 $InventoryOrderModel = new InventoryOrderModel(); break; case 4: case 6: //门店 $InventoryOrderModel = new SInventoryOrderModel(); break; } $InventoryOrderModel->updateData(['id' => $order_id], $text); $this->eliminate($param); if ($param['submit_type'] == 3) { //实时盘点 return callBack(statusCode()['success'], "操作成功", ['record_id_arr' => $record_id_arr, 'order_id' => $order_id]); } else { return callBack(statusCode()['success'], "操作成功"); } } catch (\Exception $e) { return callBack(statusCode()['error'], "操作失败"); } } /** * 盘盈入库 * @param $param * [ * user_type 3商户 4门店 6收银员 * merchant_id * store_id * operator_id 操作人id * warehousing_arr 入库商品信息 * order_number 订单号 * warehouse_id 仓库id * remarks 备注 * ] * @return mixed */ public function inventoryMore($param) { //盘盈 $more = [ 'merchant_id' => $param['merchant_id'], 'operator_id' => $param['operator_id'], 'warehouse_id' => $param['warehouse_id'], 'remarks' => $param['remarks'] ? $param['remarks'] : '', 'type' => 3, 'goodsList' => $param['warehousing_arr'], 'order_number' => $param['order_number'], ]; try { switch ($param['user_type']) { case 3: //商户 $more['stock'] = 3; $res = A('Api/Inventory')->MerWarehousing($more); break; case 4: case 6: //门店 $more['store_id'] = $param['store_id']; $more['user_type'] = $param['user_type']; $res = A('Api/Inventory')->Warehousing($more); break; } if ($res['status'] == 0) { return callBack(statusCode()['error'], "盘盈入库失败"); } return callBack(statusCode()['success'], "入库成功"); } catch (\Exception $e) { return callBack(statusCode()['success'], "入库失败"); } } /** * 盘亏出库 * @param $param * [ * user_type 3商户 4门店 6收银员 * merchant_id * store_id * operator_id 操作人id * stock_arr 入库商品信息 * order_number 订单号 * warehouse_id 仓库id * remarks 备注 * ] * @return mixed */ public function inventoryLess($param) { //盘亏 $loss = [ 'merchant_id' => $param['merchant_id'], 'operator_id' => $param['operator_id'], 'warehouse_id' => $param['warehouse_id'], 'remarks' => $param['remarks'] ? $param['remarks'] : '', 'goodsList' => $param['stock_arr'], 'order_number' => $param['order_number'], 'type' => 2 ]; try { switch ($param['user_type']) { case 3: //商户 $res = A('Api/Inventory')->MerStockOut($loss); break; case 4: case 6: //门店 $loss['store_id'] = $param['store_id']; $loss['user_type'] = $param['user_type']; $res = A('Api/Inventory')->stockOut($loss); break; } if ($res['status'] == 0) { return callBack(statusCode()['error'], "盘亏出库失败"); } return callBack(statusCode()['success'], "出库成功"); } catch (\Exception $e) { return callBack(statusCode()['success'], "出库失败"); } } /** * 提交盘点 * @param $param * [ * operator_type 1后台端 2收银端 3助手端 * user_type 3商户 4门店 6收银员 * merchant_id * store_id * supplier_type 1普通供货商 2寄售供货商 * order_id 盘点单id * order_number 盘点单号 * goodsList 商品信息 * submit_type 1盘点 2保存草稿箱 3实时盘点 * ] * @return mixed */ public function inventorySubmit($param) { $merchant_id = $param['merchant_id']; $store_id = $param['store_id'] ? $param['store_id'] : 0; $supplier_type = $param['supplier_type'] ? $param['supplier_type'] : 1; $submit_type = $param['submit_type']; $goodsList = $param['goodsList']; $order_id = $param['order_id']; $order_number = $param['order_number']; $warehouse_id = $param['warehouse_id']; $time = $_SERVER['REQUEST_TIME']; $moneyTotal = 0; //盈亏金额 $numTotal = 0; //盈亏数量 $warehousing_arr = []; //入库的商品 $stock_arr = []; //出库的商品 $record_id_arr = []; //商品记录id集合 try { switch ($param['user_type']) { case 3: //商户 $InventoryGoodsModel = new InventoryGoodsModel(); break; case 4: case 6: //门店 $InventoryGoodsModel = new SInventoryGoodsModel(); $PurchaseGoodsModel = new SPurchaseGoodsModel(); break; } $SerialClass = new SerialNumberGoods(); if (!empty($goodsList)) { foreach ($goodsList as $key => &$val) { $content = [ 'merchant_id' => $merchant_id, 'warehouse_id' => $warehouse_id, 'inventory_order_id' => $order_id, 'inventory_order_number' => $order_number, 'add_time' => $time, 'goods_class_id' => $val['goods_class_id'], 'goods_id' => $val['goods_id'], 'goods_name' => $val['goods_name'], 'goods_number' => $val['goods_number'], 'goods_code' => $val['goods_code'], 'company' => $val['company'], 'attribute_state' => $val['attribute_state'], 'pricing_method' => $val['pricing_method'], 'goods_num' => $val['goods_num'], 'cost_price' => $val['cost_price'], 'inventory_num' => $val['inventory_num'], 'remarks' => $val['remarks'] ? $val['remarks'] : '', 'serial_number_state' => $val['serial_number_state'] ? $val['serial_number_state'] : 0 ]; if (in_array($param['user_type'], ['4', '6'])) { //门店 $content['store_id'] = $store_id; $content['purchase_order_id'] = $val['purchase_order_id'] ? $val['purchase_order_id'] : 0; } $num = round($val['inventory_num'] - $val['goods_num'], 3); if ($num > 0) { $content['type'] = 1; } else if ($num < 0) { $content['type'] = 2; } else { $content['type'] = 0; } $content['num'] = $num; $content['subtotal'] = round($num * $val['cost_price'], 2); if ($val['attribute_state'] == 2) { $content['sku_id'] = $val['sku_id']; $content['sku_name'] = $val['sku_name']; $content['sku_goods_number'] = $val['sku_goods_number']; $content['sku_code'] = $val['sku_code']; $content['sku_num'] = $val['sku_num']; $content['sku_id_list'] = $val['sku_id_list']; } if (!empty($val['inventory_goods_id'])) { $InventoryGoodsModel->updateData(array('id' => $val['inventory_goods_id']), $content); //串号信息 if ($val['serial_number_state'] == 1) { $SerialClass->inventorySerialDelete([ 'user_type' => $param['user_type'], 'id' => $val['inventory_goods_id'], 'goods_id' => $val['goods_id'], 'sku_id' => $val['sku_id'] ]); } $outside_id = $val['inventory_goods_id']; } else { $success = $InventoryGoodsModel->addData($content); if ($success['status'] != 1) { return callBack($success['error'], $val['goods_name'] . "添加失败"); } $outside_id = $success['data']; if ($param['submit_type'] == 3) { //实时盘点 array_push($record_id_arr, [ 'attribute_state' => $val['attribute_state'], 'goods_id' => $val['goods_id'], 'sku_id' => $val['sku_id'], 'inventory_goods_id' => $success['data'], ]); } } //串号记录 if ($val['serial_number_state'] == 1 && $val['inventory_num'] > 0) { $serialResult = $SerialClass->inventorySerial([ 'user_type' => $param['user_type'], 'merchant_id' => $merchant_id, 'store_id' => $store_id ? $store_id : 0, 'outside_id' => $outside_id, 'goods_id' => $val['goods_id'], 'sku_id' => $val['sku_id'], 'add_time' => $time, 'serial_list' => $val['serial_list'] ]); if ($serialResult['status'] != 1) { return callBack(statusCode()['error'], $val['goods_name'] . $val['sku_name'] . '串号记录添加失败'); } } $moneyTotal += $content['subtotal']; $numTotal += $num; if ($submit_type == 1) { //盘点 if ($num == 0 && $val['serial_number_state'] == 1) { $serialResult = $SerialClass->inventoryScreen([ 'user_type' => $param['user_type'], 'merchant_id' => $merchant_id, 'store_id' => $store_id, 'goods_id' => $val['goods_id'], 'sku_id' => $val['sku_id'] ? $val['sku_id'] : 0, 'type' => 3, 'num' => 0, 'serial_list' => $val['serial_list'], 'add_time' => $time ]); if ($serialResult['status'] != 1) { return $serialResult; } } else if ($num > 0) { //盘盈 $new_arr = $content; //串号处理 if ($val['serial_number_state'] == 1) { $serialResult = $SerialClass->inventoryScreen([ 'user_type' => $param['user_type'], 'merchant_id' => $merchant_id, 'store_id' => $store_id, 'goods_id' => $val['goods_id'], 'sku_id' => $val['sku_id'] ? $val['sku_id'] : 0, 'type' => 1, 'num' => $num, 'serial_list' => $val['serial_list'], 'add_time' => $time ]); if ($serialResult['status'] != 1) { return $serialResult; } $new_arr['serial_list'] = $serialResult['data']['serial_arr']; //入库串号信息 } $new_arr['id'] = $val['id']; $new_arr['warehouse_price'] = $val['cost_price']; $new_arr['warehouse_num'] = $num; if ($supplier_type == 2 && !empty($val['purchase_order_id'])) { //寄售门店 $pur_map = array( 'store_id' => $store_id, 'goods_id' => $val['goods_id'], 'purchase_order_id' => $val['purchase_order_id'] ); if ($val['attribute_state'] == 2) { $pur_map['sku_id'] = $val['sku_id']; } $pru_info = $PurchaseGoodsModel->getFieldInfo($pur_map, "supplier_id,purchase_price"); $new_arr['warehouse_price'] = $pru_info['purchase_price'] ? $pru_info['purchase_price'] : $val['cost_price']; $new_arr['supplier_id'] = $pru_info['supplier_id']; } array_push($warehousing_arr, $new_arr); } else if ($num < 0) { //盘亏 $new_arr = $content; if ($val['serial_number_state'] == 1) { $serialResult = $SerialClass->inventoryScreen([ 'user_type' => $param['user_type'], 'merchant_id' => $merchant_id, 'store_id' => $store_id ? $store_id : 0, 'goods_id' => $val['goods_id'], 'sku_id' => $val['sku_id'] ? $val['sku_id'] : 0, 'type' => 2, 'num' => abs($num), 'serial_list' => $val['serial_list'], 'add_time' => $time ]); if ($serialResult['status'] != 1) { return $serialResult; } $new_arr['serial_list'] = $serialResult['data']['serial_arr']; //出库串号信息 } $new_arr['id'] = $val['id']; $new_arr['stock_price'] = $val['cost_price']; $new_arr['output_num'] = round($val['goods_num'] - $val['inventory_num'], 3); array_push($stock_arr, $new_arr); } unset($new_arr); } } } return callBack(statusCode()['success'], "盘点记录保存成功", [ 'warehousing_arr' => $warehousing_arr, 'stock_arr' => $stock_arr, 'moneyTotal' => $moneyTotal, 'numTotal' => $numTotal, 'record_id_arr' => $record_id_arr ]); } catch (\Exception $e) { return callBack(statusCode()['error'], "操作失败"); } } /** * 查询盘点单号 * @param $param * [ * user_type 3商户 4门店 6收银员 * order_id 盘点单id * ] * @return mixed */ public function searchOrderNumber($param) { try { switch ($param['user_type']) { case 3: //商户 $InventoryOrderModel = new InventoryOrderModel(); break; case 4: case 6: //门店 $InventoryOrderModel = new SInventoryOrderModel(); break; } $order_info = $InventoryOrderModel->getFieldInfo(['id' => $param['order_id']], "order_number,status"); if (empty($order_info)) { return callBack(statusCode()['error'], "未找到该盘点单号"); } if ($order_info['status'] == 1) { return callBack(statusCode()['error'], "该订单已盘点完成"); } return callBack(statusCode()['success'], "查询成功", $order_info['order_number']); } catch (\Exception $e) { return callBack(statusCode()['error'], "查询失败"); } } /** * 创建订单 * @param $param * [ * user_type 3商户 4门店 6收银员 * merchant_id * store_id * warehouse_id 销售仓id * remarks 备注 * operator_id 操作人id * * ] * @return mixed */ public function createOrder($param) { $data = [ 'merchant_id' => $param['merchant_id'], 'warehouse_id' => $param['warehouse_id'], 'remarks' => $param['remarks'], 'add_time' => time(), 'operator_id' => $param['operator_id'] ]; try { switch ($param['user_type']) { case 3: //商户 $InventoryOrderModel = new InventoryOrderModel(); break; case 4: case 6: //门店 $data['store_id'] = $param['store_id']; if ($param['user_type'] == 6) { //收银员 $data['operator_type'] = 1; } $InventoryOrderModel = new SInventoryOrderModel(); break; } $InventoryOrder = $InventoryOrderModel->addData($data); if ($InventoryOrder['status'] == 0) { return callBack(statusCode()['error'], "订单创建失败"); } return callBack(statusCode()['success'], "创建成功", $InventoryOrder['data']); } catch (\Exception $e) { return callBack(statusCode()['error'], "操作失败"); } } /** * 盘点参数验证 * @param $param * [ * operator_type 1后台端 2收银端 3助手端 * user_type 3商户 4门店 6收银员 * merchant_id * store_id * supplier_type 1普通供货商 2寄售供货商 * goodsList 商品信息 * submit_type 1盘点 2保存草稿箱 3实时盘点 * order_id 订单id * ] * @return mixed */ public function goodsVerify($param) { $VerifyClass = new VerifyParam(); //参数验证 $verifyResult = $VerifyClass->identityVerify($param); if ($verifyResult['status'] != 1) { return $verifyResult; } if (!empty($param['order_id'])) { $cacheResult = $this->testLock($param); if ($cacheResult['status'] != 1) { return $cacheResult; } $orderStateResult = $this->getOrderState($param); if ($orderStateResult['status'] != 1) { return $orderStateResult; } } if (!in_array($param['submit_type'], ['1', '2', '3'])) { return callBack(statusCode()['error'], "未知的提交类型"); } if (empty($param['goodsList']) && empty($param['order_id'])) { return callBack(statusCode()['error'], "缺少商品信息"); } if (empty($param['goodsList']) && empty($param['order_id'])) { return callBack(statusCode()['error'], "请选择盘点的商品"); } if (count($param['goodsList']) > 500) { return callBack(statusCode()['error'], "一次盘点商品上限为500种商品"); } try { $WarehouseClass = new Warehouse(); $warehouseResult = $WarehouseClass->getSaleWarehouseId([ 'user_type' => $param['user_type'] == '6' ? '4' : $param['user_type'], 'merchant_id' => $param['merchant_id'], 'store_id' => $param['store_id'] ? $param['store_id'] : 0 ]); if ($warehouseResult['status'] != 1) { return callBack(statusCode()['error'], "请创建供给仓"); } $data = []; $goodsList = $param['goodsList']; $reg1 = "/^[0-9]+(.[0-9]{1,2})?$/"; $reg2 = "/^[0-9]+(.[0-9]{1,3})?$/"; $reg3 = "/^\+?[0-9][0-9]*$/"; $SerialClass = new SerialNumberGoods(); foreach ($goodsList as $val) { if (empty($val['cost_price'])) { return callBack(statusCode()['error'], "成本价有误,未入库的商品禁止盘点"); } if (!preg_match($reg1, $val['cost_price'])) { return callBack(statusCode()['error'], "请输入正确价格"); } switch ($val['attribute_state']) { case 1: //无规格 if ($val['pricing_method'] == 1) { //无称重 if (!preg_match($reg3, $val['inventory_num'])) { return callBack(statusCode()['error'], $val['goods_name'] . "请输入正确库存"); } if (!preg_match($reg3, abs($val['goods_num']))) { return callBack(statusCode()['error'], $val['goods_name'] . "商品称重属性改变,库存有误"); } } else { if (!preg_match($reg2, $val['inventory_num'])) { return callBack(statusCode()['error'], $val['goods_name'] . "请输入正确盘点数量"); } if (!preg_match($reg2, abs($val['goods_num']))) { return callBack(statusCode()['error'], $val['goods_name'] . "商品称重属性改变,库存有误"); } } break; case 2: //规格 if (!preg_match($reg3, $val['inventory_num'])) { return callBack(statusCode()['error'], $val['goods_name'] . $val['sku_name'] . "请输入正确盘点数量"); } if (!preg_match($reg3, abs($val['goods_num']))) { return callBack(statusCode()['error'], $val['goods_name'] . $val['sku_name'] . "商品称重属性改变,库存有误"); } break; default: return callBack(statusCode()['error'], $val['goods_name'] . "商品规格属性错误,禁止盘点"); break; } //串号信息 if ($val['serial_number_state'] == 1 && $val['inventory_num'] != 0 && empty($val['serial_list'])) { return callBack(statusCode()['error'], $val['goods_name'] . "商品串号信息有误"); } if ($val['serial_number_state'] == 1 && !empty($val['serial_list'])) { $serialResult = $SerialClass->serialVerify([ 'serial_list' => $val['serial_list'], 'data' => $data ]); if ($serialResult['status'] != 1) { return callBack(statusCode()['error'], $val['goods_name'] . $val['sku_name'] . $serialResult['message']); } $data = $serialResult['data']; } if (($param['user_type'] == 4 || $param['user_type'] == 6) && $param['supplier_type'] == 2 && ($val['inventory_num'] > $val['goods_num']) && !empty($val['pur_id']) && empty($val['purchase_order_id'])) { //寄售门店 return callBack(statusCode()['error'], $val['goods_name'] . $val['sku_name'] . "请与批次号绑定"); } } return callBack(statusCode()['success'], "验证成功", [ 'warehouse_id' => $warehouseResult['data'] ]); } catch (\Exception $e) { return callBack(statusCode()['error'], "验证失败"); } } /** * 查看订单状态 * @param $param * [ * user_type 3商户 4门店 6收银员 * order_id 订单id * merchant_id * store_id * ] * @return mixed */ public function getOrderState($param) { $where = [ 'merchant_id' => $param['merchant_id'], 'id' => $param['order_id'] ]; try { switch ($param['user_type']) { case 3: //商户 $InventoryModel = new InventoryOrderModel(); break; case 4: case 6: //门店 $where['store_id'] = $param['store_id']; $InventoryModel = new SInventoryOrderModel(); break; } $status = $InventoryModel->getFindField($where, "status"); if ($status == 1) { return callBack(statusCode()['error'], "该订单已提交盘点,禁止操作"); } else { return callBack(statusCode()['success'], "可以操作"); } } catch (\Exception $e) { return callBack(statusCode()['error'], "操作失败"); } } /** * 获取缓存key * @param $param * [ * order_id 订单id * user_type 3商户 4门店 6收银员 * merchant_id * store_id * ] * @return string */ public function getKey($param) { switch ($param['user_type']) { case 3: //商户 $key_name = 'retail_inventory_merchant_id_' . $param['merchant_id'] . '_order_id_' . $param['order_id']; break; case 4: case 6: //门店 $key_name = 'retail_inventory_merchant_id_' . $param['merchant_id'] . '_store_id_' . $param['store_id'] . '_order_id_' . $param['order_id']; break; } return $key_name; } /** * 检测锁 * @param $param * [ * order_id 订单id * user_type 3商户 4门店 6收银员 * merchant_id * store_id * ] * @return mixed */ public function testLock($param) { if (C('IS_SET_REDIS')) { $key_name = $this->getKey($param); $CacheClass = new CacheHandle(); $CacheClass->testingKey($key_name); $keyState = $CacheClass->isExists($key_name); if ($keyState == 1) { return callBack(statusCode()['error'], "该订单正在操作中,请稍后重试"); } else { return callBack(statusCode()['success'], "可以操作"); } } else { return callBack(statusCode()['success'], "可以操作"); } } /** * 添加缓存 * @param $param * [ * user_type 3商户 4门店 6收银员 * merchant_id * store_id * order_id * ] */ public function addLock($param) { if (C('IS_SET_REDIS')) { $arr = [ 'merchant_id' => $param['merchant_id'], 'order_id' => $param['order_id'] ]; if ($param['user_type'] != 3) { $arr['store_id'] = $param['store_id']; } $key_name = $this->getKey($param); $ApiRedis = new RedisController(); $ApiRedis::$redis->multi(); //开启事务 $CacheClass = new CacheHandle(); $CacheClass->addTimeCache($key_name, 60, $arr); } } /** * 清除缓存 * @param $param * [ * user_type 3商户 4门店 6收银员 * merchant_id * store_id * order_id * ] */ public function eliminate($param) { if (C('IS_SET_REDIS')) { $key_name = $this->getKey($param); $CacheClass = new CacheHandle(); $CacheClass->eliminateCache($key_name); $ApiRedis = new RedisController(); $ApiRedis::$redis->exec(); } } }