adminOperateLogger = new AdminOperate([ 'fetchClass' => ApproachOrder::class, ]); } /** * @inheritdoc */ public function rules() { return [ [['sn', 'expressCompany', 'orderTrackNo', 'status', 'remark','type','addressId','payType','goodsId','goodsNum', 'payPassword','userName','consignee','acceptMobile','province','city','county','cityName','detailaddress', 'consigneeIdNo', 'consigneeRealName'], 'trim'], [['sn', 'expressCompany', 'orderTrackNo', 'status', 'remark','type','addressId','payType','goodsId','goodsNum', 'payPassword','userName','consignee','acceptMobile','province','city','county','detailaddress', 'consigneeIdNo', 'consigneeRealName'], 'required'], [['status'], 'isStatus'], [['addressId'], 'isAddress'], [['payType'], 'isPayType'], ]; } public function attributeLabels() { return [ 'sn' => '订单号', 'expressCompany' => '快递公司', 'orderTrackNo' => '快递单号', 'status' => '状态', 'remark' => '备注', 'type' => '订单类型', 'addressId' => '收货地址', 'payType' => '支付方式', 'goodsId' => '商品ID', 'goodsNum' => '商品数量', 'userName' => '复消会员编号', 'consignee' => '收货人', 'acceptMobile' => '收货电话', 'province' => '省', 'city' => '市', 'county' => '区', 'detailaddress' => '收货详细地址', ]; } /** * 指定校验场景 * @return array */ public function scenarios() { $parentScenarios = parent::scenarios(); $customScenarios = [ // 管理员修改订单状态 'adminStatus' => ['sn', 'status'], // 校验订单支付 'verifyPay' => ['sn', 'status', 'note'], // 会员下单 'userOrder' => ['type','addressId', 'payType','goodsId','goodsNum', 'note', 'consigneeIdNo', 'consigneeRealName'], ]; return array_merge($parentScenarios, $customScenarios); } /** * 校验之前 * @return bool */ public function beforeValidate() { $parentValidate = parent::beforeValidate(); if ($this->sn) { $this->_model = ApproachOrder::findOne(['SN' => $this->sn]); if (!$this->_model) { $this->addError('sn', '订单不存在'); return false; } } return $parentValidate; } /** * 判断收货地址是否存在 * @param $attribute */ public function isAddress($attribute){ if (!$receiveAddress = ReceiveAddress::find()->where('ID=:ID', [':ID' => $this->addressId])->asArray()->one()) { $this->addError($attribute, '收货地址不存在'); } else { $this->_address = $receiveAddress; // 邮编根据最后一级的行政地区获得, 如果没有则向上一级搜索 $this->zipCode = Region::getZipCode($receiveAddress['COUNTY']); if (!$this->zipCode) { $this->zipCode = Region::getZipCode($receiveAddress['CITY']); if (!$this->zipCode) { $this->addError($attribute, '收货地址邮编异常,请联系客服人员'); } } } } /** * 判断支付方式 * @param $attribute * @throws Exception */ public function isPayType($attribute) { if ($this->payType && !in_array($this->payType, array_values(ShopGoods::BANK_CODE))) { $this->addError('支付方式错误'); return; } // 一个订单只能包含一类商品 $goods = ShopGoods::find()->select('ID,CATE_ID')->where(['in', 'ID', $this->goodsId])->andWhere(['STATUS' => 1])->asArray()->all(); if (!$goods) { throw new Exception('商品已下架'); } $goodsCategoryType = array_unique(array_column($goods, 'CATE_ID')); if (count($goodsCategoryType) > 1) { $this->addError($attribute, '订单不能包含多种商品分类'); return; } } /** * 校验类型 * @param $attribute * @throws Exception */ public function isStatus($attribute){ if ($this->status && ($this->status != \Yii::$app->params['orderStatus']['notPaid']['value']) && ($this->status != \Yii::$app->params['orderStatus']['paid']['value'])) { $this->addError($attribute, '订单状态类型错误'); throw new Exception('商品已下架'); } } /** * 校验iPay88支付,更新订单状态.同步到正式订单. */ public function verifyPayOnline(): ?ApproachOrder { if (!$this->validate()) { return null; } LoggerTool::info([$this->sn, $this->note]); // TODO: 支付校验 $db = \Yii::$app->db; $transaction = $db->beginTransaction(); try { // 更新准订单状态为已支付 $this->_model->STATUS = $this->status; $this->_model->NOTE = json_encode($this->note); $this->_model->PAY_AT = time(); if (!$this->_model->save()) { throw new Exception(Form::formatErrorsForApi($this->_model->getErrors())); } // 同步准订单到正式订单 Order::insertOne($this->_model->toArray()); // 同步准订单商品到正式订单商品 $approachOrderGoods = ApproachOrderGoods::findAllAsArray('ORDER_SN = :ORDER_SN', [':ORDER_SN' => $this->sn]); OrderGoods::batchInsert($approachOrderGoods); // 删除中间表 ApproachOrder::deleteAll('SN=:SN', [':SN' => $this->sn]); ApproachOrderGoods::deleteAll('ORDER_SN = :ORDER_SN', [':ORDER_SN' => $this->sn]); $transaction->commit(); } catch (Exception $e) { $transaction->rollBack(); $this->addError('edit', $e->getFile() . ' ' . $e->getMessage()); return null; } return $this->_model; } public function verifyPayUPOP(): ?bool { if (!$this->validate()) { return null; } // 支付校验 $db = \Yii::$app->db; $transaction = $db->beginTransaction(); try { // 更新准订单状态为已支付 $this->_model->STATUS = $this->status; $this->_model->NOTE = json_encode($this->note); $this->_model->PAY_AT = strtotime($this->note['pay_time']); if (!$this->_model->save()) { throw new Exception(Form::formatErrorsForApi($this->_model->getErrors())); } // 同步准订单到正式订单 Order::insertOne($this->_model->toArray()); // 同步准订单商品到正式订单商品 $approachOrderGoods = ApproachOrderGoods::findAllAsArray('ORDER_SN = :ORDER_SN', [':ORDER_SN' => $this->sn]); OrderGoods::batchInsert($approachOrderGoods); // 删除中间表 ApproachOrder::deleteAll('SN=:SN', [':SN' => $this->sn]); ApproachOrderGoods::deleteAll('ORDER_SN = :ORDER_SN', [':ORDER_SN' => $this->sn]); $transaction->commit(); return true; } catch (Exception $e) { $transaction->rollBack(); $this->addError('edit', $e->getFile() . ' ' . $e->getMessage()); return null; } } /** * BV分期 * * */ private function _pvSplit($oPv){ $sysConfig = Cache::getSystemConfig(); $mesureUpCondition = $sysConfig['monthPcsPvFxCondition']['VALUE']; if ($oPv > $mesureUpCondition) { $currentPv = $oPv % $mesureUpCondition + $mesureUpCondition; $remainPv = $oPv - $currentPv; } else { $currentPv = $oPv; $remainPv = 0; } return [ 'current' => $currentPv, 'remain' => $remainPv ]; } /** * 复销 * @throws Exception * @throws \yii\db\Exception */ public function add() { if(!$this->validate()){ return null; } $ids = $this->goodsId; $totalAmount = 0; $totalPv = 0; $totalRealPv = 0; $this->_remainPv = 0; $cateId = []; foreach ($this->goodsNum as $k => $v) { if ($v) { $goods = ShopGoods::findOneAsArray('ID=:ID AND STATUS=1',[':ID'=> $ids[$k]]); if (!$goods) { throw new Exception('商品已下架'); } $cateId[] = $goods['CATE_ID']; if ($goods['STORE_NUMS'] > 0) { $discount = $goods['SELL_DISCOUNT']; $realPrice = $goods['SELL_PRICE'] * $discount; $realPv = $goods['PRICE_PV'] * $discount; if ($goods['PV_SPLIT'] == 1) { // 当商品为PV分期时 $pvSplit = $this->_pvSplit($realPv); $currentPv = $pvSplit['current']; $remainPv = $pvSplit['remain']; $totalPv += $currentPv * intval($v); $totalRealPv += $realPv * intval($v); $this->_remainPv += $remainPv * intval($v); } else { $currentPv = $goods['PRICE_PV']; $totalPv += $realPv * intval($v); $totalRealPv += $realPv * intval($v); $remainPv = 0; $this->_remainPv += 0; } $totalAmount += $realPrice * intval($v); $this->_orderGoods[] = [ 'GOODS_ID' => $goods['ID'], 'PRICE' => $goods['SELL_PRICE'], 'PV' => $currentPv, 'REAL_PRICE' => $realPrice, 'REAL_PV' => $realPv, 'REMAIN_PV' => $remainPv, 'POINT' => $goods['POINT'], 'BUY_NUMS' => intval($v), 'SKU_CODE' => $goods['GOODS_NO'], 'GOODS_TITLE' => $goods['GOODS_NAME'] ]; } } } if (count(array_unique($cateId)) > 1) { throw new Exception('海内商品、海外商品只能选择一种'); } $this->_decAmount = $totalAmount; $this->_decPv = $totalPv; $this->_realPv = $totalRealPv; $this->_freight = ($totalAmount>=300) ? 0 : 15; $this->_payAmount = $this->_decAmount + $this->_freight; $db = \Yii::$app->db; $transaction = $db->beginTransaction(); // 支付减库存 foreach ($this->goodsNum as $k => $v) { if ($v) { $goods = ShopGoods::findOneAsArray('ID=:ID AND STATUS=1', [':ID'=> $ids[$k]]); if (!$goods) { throw new Exception('商品已下架'); } if ($goods['STORE_NUMS'] >= $this->goodsNum[$k]) { $data = ShopGoods::find()->where(['ID' => $ids[$k]])->one(); $goods_store_nums = $data->STORE_NUMS - $this->goodsNum[$k]; $data->STORE_NUMS = $goods_store_nums; $data->update(); //下单后库存小于等于0 商品下架 if ($goods_store_nums <= 0) { $data->STATUS = 0; $data->UPDATED_AT = Date::nowTime(); $data->update(); } } else { throw new Exception($goods['GOODS_NAME'].'库存不足,无法购买商品'); } } } try { // 写入订单 if (!$orderResult = $this->addOrder()) { throw new Exception(Form::formatErrorsForApi($orderResult->getErrors())); } // TODO: 获取iPay88所需参数 // $orderSn = $orderResult->SN; $transaction->commit(); return $orderResult; }catch (\Exception $e){ $transaction->rollBack(); $this->addError('add', $e->getMessage()); return null; } } /** * 复销订单 * @throws Exception */ public function addOrder() { $periodObj = Period::instance(); $nowPeriodNum = $periodObj->getNowPeriodNum(); $nowCalcMonth = $periodObj->getYearMonth($nowPeriodNum); $userId = \Yii::$app->user->id; $userName = Info::getUserNameByUserId($userId); $userRealName = Info::getUserRealNameByUserId($userId); $userMobile = Info::getUserMobileByUserId($userId); $userEmail = Info::getUserEmailByUserId($userId); // 加入订单信息 $warehouse = Region::getWarehouseByCode($this->_address['PROVINCE']);//仓库 if(!$warehouse){ throw new Exception('地区暂时不支持配送,具体联系客服'); } $ordNo = $this->_generateSn(); $orderModel = new ApproachOrder(); $orderModel->SN = 'OS' . $ordNo; $orderModel->DEC_SN = 'DS' . $ordNo; $orderModel->ORDER_TYPE = $this->type; $orderModel->USER_ID = $userId; $orderModel->USER_NAME = $userName; $orderModel->ORDER_AMOUNT = $this->_decAmount; $orderModel->PV = $this->_decPv; $orderModel->PAY_AMOUNT = $this->_payAmount; $orderModel->PAY_PV = $this->_decPv; $orderModel->REMAIN_PV = $this->_remainPv; $orderModel->PAY_AT = 0; $orderModel->PAY_TYPE = $this->payType; $orderModel->PERIOD_NUM = $nowPeriodNum; $orderModel->P_CALC_MONTH = Date::ociToDate($nowCalcMonth, Date::OCI_TIME_FORMAT_SHORT_MONTH); $orderModel->FREIGHT = $this->_freight; $orderModel->PAY_FREIGHT = $this->_freight; $orderModel->CONSIGNEE = $this->_address['CONSIGNEE']; $orderModel->MOBILE = $this->_address['MOBILE']; $orderModel->PROVINCE = $this->_address['PROVINCE']; $orderModel->CITY = $this->_address['CITY']; $orderModel->COUNTY = $this->_address['COUNTY']; $orderModel->ADDRESS = $this->_address['ADDRESS']; $orderModel->FRONT_REMARK = $this->remark; $orderModel->WAREHOUSE = $warehouse; $orderModel->STATUS = \Yii::$app->params['orderStatus']['notPaid']['value']; $orderModel->CREATED_AT = Date::nowTime(); $orderModel->CREATE_USER = $userName; $orderModel->EMAIL = $userEmail ?: $userName.'@elken.net'; $orderModel->CONSIGNEE_ID_NO = $this->consigneeIdNo; $orderModel->CONSIGNEE_REAL_NAME = $this->consigneeRealName; $orderModel->ZIP_CODE = $this->zipCode; if(!$orderModel->save()){ $this->addErrors($orderModel->getErrors()); return false; } // 加入商品到订单商品表 foreach($this->_orderGoods as $key=>$value) { $this->_orderGoods[$key]['ORDER_SN'] = $orderModel->SN; $this->_orderGoods[$key]['P_CALC_MONTH'] = Date::ociToDate($nowCalcMonth, Date::OCI_TIME_FORMAT_SHORT_MONTH); } ApproachOrderGoods::batchInsert($this->_orderGoods); return $orderModel; } /** * 生成流水号 * @return string */ private function _generateSn() { return Date::today('Ymd') . $this->_random(10, 1); } /** * 生成随机数 * @param $length * @param int $numeric * @return string */ private function _random($length, $numeric = 0) { $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35); $seed = $numeric ? (str_replace('0', '', $seed) . '012340567890') : ($seed . 'zZ' . strtoupper($seed)); $hash = ''; $max = strlen($seed) - 1; for ($i = 0; $i < $length; $i++) { $hash .= $seed[mt_rand(0, $max)]; } return $hash; } }