100], [['remark', 'extra'], 'string', 'max' => 255], ]; } /** * {@inheritdoc} */ public function attributeLabels() { return [ 'id' => 'ID', 'mall_id' => 'Mall ID', 'store_id' => '门店id', 'user_id' => '会员id', 'order_no' => '订单编号', 'pay_status' => '支付状态', 'pay_time' => '付款时间', 'money' => '应付金额', 'pay_money' => '实付金额', 'payment_type' => '支付类型', 'amount_received' => '实收金额', 'service_money' => '服务费', 'remark' => '备注', 'extra' => '额外信息:例如优惠信息,渠道分红,经销分红', 'status' => '状态[0禁用 1启用 -1删除]', 'created_at' => '创建时间', 'updated_at' => '修改时间', ]; } public static function fieldsList($is_true=false) { $data= [ 'user_id' => '会员ID', 'nickname' => '昵称', 'pay_time' => '付款时间', 'money' => '应付金额', 'pay_money' => '实付金额', 'extra' => '优惠信息', 'amount_received' => '实收金额', 'remark' => '备注', ]; if($is_true){ $data['store_name'] = '门店名称'; } return $data; } public function getStore() { return $this->hasOne(Store::class, ['id' => 'store_id']); } /** * 异步导出至下载中心 * @DateTime 2021-11-12 16:01:25 * @param array $data * @copyright: Copyright (c) 2020 广东七件事集团 */ public static function exportHandle(array $data) { $download_id = $data['download_id'] ?? 0; $download = Download::findOne(['id' => $download_id]); if ($download) { try { $params = json_decode($download->params, true); $filename = $download->name; $type = $download->type; $model = self::find(); $model->where(['mall_id' => $params['mall_id']]); $model->andWhere(['store_id' => $params['store_id']]); if (!empty($params['start'])) $model->andWhere(['>=', 'pay_time', strtotime($params['start'])]); if (!empty($params['end'])) $model->andWhere(['<=', 'pay_time', strtotime($params['end'])]); if (!empty($params['min'])) $model->andWhere(['>=', 'pay_money', $params['min']]); if (!empty($params['max'])) $model->andWhere(['<=', 'pay_money', $params['max']]); if (!empty($params['keyword'])) { $user_list = User::lists(['where' => [['mall_id' => $params['mall_id']], [ 'or', ['like', 'username', $params['keyword']], ['like', 'nickname', $params['keyword']], ]], 'select' => 'id']); $user_ids = array_column($user_list, 'id'); $model->andWhere(['in', 'user_id', $user_ids]); } $model->with(['user']); $fields = $params['fields']; $fields_arr = self::fieldsList(); $have_select_field_arr = []; foreach ($fields as $value) { $have_select_field_arr[] = $fields_arr[$value]; } $csv = new CsvTool(); $csv->filename = $filename; $csv->file_dirname = DownloadEnum::getTypeStorageDirMap($type); $csv->export_mode = CsvTool::EXPORT_MODE_ASYNC; $csv->header = $have_select_field_arr; foreach ($model->batch() as $orders) { // $users 是一个包含100条或小于100条用户表数据的数组 empty($csv->header) && $csv->header = array_keys($orders[0]); $csv->data = array_map(function ($order) use ($fields) { $row = []; foreach ($fields as $field) { if ($field == 'nickname') { $row[] = $order['user']['nickname']; } else if ($field == 'extra') { $extra = json_decode($order['extra'], true); $extra_content = ''; if ($extra) { foreach ($extra as $k => $v) { if ($v) { switch ($k) { case "discount_money": $extra_content .= ' 优惠:' . $v; break; case "agent_commission": $extra_content .= ' 渠道分红:' . $v; break; case "distribution_commission": $extra_content .= ' 分销分红:' . $v; break; } } } } $row[] = $extra_content; } else if ($field == 'pay_time') { $row[] = !empty($order['pay_time']) ? date('Y-m-d H:i:s', $order['pay_time']) : ''; } else { if ((isset($order[$field]))) $row[] = $order[$field]; } } return $row; }, $orders); $csv->export(); } $url = $csv->upload($params['mall_id'], $csv->relative_filename); $download->status = 2; $download->url = $url; $download->num = $csv->line_num; $download->size = $csv->file_size; $res = $download->save(); return true; } catch (\PHPUnit\Util\Exception $e) { $download->status = 3; self::setStaticError($e->getMessage()); return false; } } } public function getUser() { return $this->hasOne(User::class, ['id' => 'user_id']); } public function getDetail() { return $this->hasMany(StoreCashierOrderDetail::class, ['cashier_order_id' => 'id']); } public static function setData(array $params) { try { if (!empty($params['id'])) { $model = self::findOne(['id' => $params['id'], 'status' => [StatusEnum::ENABLED, StatusEnum::DISABLED]]); if (empty($model)) throw new \Exception('商品不存在或已删除'); } else { $model = new self(); $model->loadDefaultValues(); } if (!$model->load($params, '')) throw new \Exception($model->getErrorMessage()); if (!$model->save()) throw new \Exception($model->getErrorMessage()); return $model; } catch (\Exception $e) { self::$static_error = $e->getMessage(); return false; } } public static function preview($params) { $marketing = []; $extra = StoreCashierExtra::findOne(['mall_id' => $params['mall_id'], 'store_id' => $params['store_id'], 'status' => StatusEnum::ENABLED]); $deduct = []; $dis_pay_money = $params['money']; $deduct['coupon']['is_can_use'] = 0; $deduct['score']['is_can_use'] = 0; $cashier = \Yii::$app->services->setting->addons->get($params['mall_id'], StoreEnum::ADDONS_NAME, 'cashier'); $members = []; if(!empty($cashier['member_status'])){ $members = json_decode($cashier['members'], true); } $store_setting = StoreSettings::findOne(['mall_id' => $params['mall_id'], 'store_id' => $params['store_id'],'status'=>StatusEnum::ENABLED]); if(!empty($store_setting['cashier_member_status'])){ $members = json_decode($store_setting['cashier_member_settings'], true); } if(!empty($members)&&is_array($members)){ $members = array_column($members,null,'level'); } list($discount_money,$discount) = self::computeMemberPrice($members,$dis_pay_money,$params['user']['level']); $deduct['member_price'] = ['money'=>-$discount_money, 'name'=>'会员优惠']; if (!empty($extra['preferential_deduction'])) { $score_deduct_setting = json_decode($extra['score_deduct_setting'], true); switch ($score_deduct_setting['type']) { case 1: case 2: $deduct['coupon']['is_can_use'] = 1; $coupon_list = self::getCanUseCouponList( $params['user_id'], $extra,$dis_pay_money); $deduct['coupon']['list'] = $coupon_list; break; case 3: break; } } if (MallAddons::isInstall($params['mall_id'], AddonsEnum::ADDONS_NAME_MEMBERS_CARD)) { $members_card_obj = new \addons\MembersCard\common\logic\order\MemberCardMarketing(); $deduct['member_card']['list'] = $members_card_obj::getMemberCardList($params['user_id'],$params['mall_id']); } if (!empty($params['user_coupon_id'])) { $deduct_money = 0; self::useCouponDiscount($params['user_id'], $params['user_coupon_id'], $params['money'], $dis_pay_money, $deduct_money); $deduct['coupon']['discount_money'] = -$deduct_money; } $score_name = \Yii::$app->services->setting->mall->get($params['mall_id'], 'score.score_name'); if(empty($score_name)) $score_name = '积分'; if (isset($params['user_card_id']) && !empty($params['user_card_id']) && !empty($params['user_card_money'])) { $deduct_money = 0; $members_card_obj = new \addons\MembersCard\common\logic\order\MemberCardMarketing(); $members_card_obj::storeCashierCompute($params['mall_id'],$params['user_id'], $params['user_card_id'], $dis_pay_money, $deduct_money,$params['user_card_money']); if($deduct_money){ $deduct['member_card']['name'] = '折扣价'; $deduct['member_card']['discount_money'] = -$deduct_money; } } $platform_basic_score_deduction = \Yii::$app->services->setting->addons->get($params['mall_id'], StoreEnum::ADDONS_NAME, 'payment.score_deduction'); $platform_basic_score_deduction = is_array($platform_basic_score_deduction) ? $platform_basic_score_deduction : json_decode($platform_basic_score_deduction, true); $store_settings_row = StoreSettings::getOne([['mall_id' => $params['mall_id']], ['store_id' => $params['store_id']], ['status' => StatusEnum::ENABLED]], true); !empty($store_settings_row['score_deduction']) && $store_setting = json_decode($store_settings_row['score_deduction'], true); $effective = !empty($store_setting['is_alone_score_deduction']) && !empty($store_setting['effective']) ? $store_setting['effective'] : $platform_basic_score_deduction['effective']; if (!empty($platform_basic_score_deduction['is_score_deduction']) && !empty($platform_basic_score_deduction['score_balance_ratio']) && !empty($store_setting['is_score_deduction']) && $effective != 3) { $deduct['score']['is_can_use'] = 0; if (!empty($platform_basic_score_deduction['deduction_type'])) { // 判断平台是否为门店设置了最高抵扣比例,没有则走全局的 $deduction_ratio = !empty($platform_basic_score_deduction['store_limit_type']) && isset($platform_basic_score_deduction['store_limit_stores_deduction'][$params['store_id']]) && is_numeric($platform_basic_score_deduction['store_limit_stores_deduction'][$params['store_id']]) ? $platform_basic_score_deduction['store_limit_stores_deduction'][$params['store_id']] : $platform_basic_score_deduction['max_deduction_percent']; // 判断门店独立设置最高抵扣比例 isset($store_setting) && isset($store_setting['max_deduction_percent']) && !empty($store_setting['is_alone_score_deduction']) && is_numeric($store_setting['max_deduction_percent']) && $deduction_ratio = $store_setting['max_deduction_percent']; }else{ $store_setting_service_obj = (new StoreSettingService(['mall_id' => $params['mall_id']])); $store_score_deduction = $store_setting_service_obj->getDeductionProportion(['store_id' => [$params['store_id']], 'order_type' => 'store_cashier_order']); if (!empty($store_score_deduction[$params['store_id']])){ $deduction_ratio = $store_setting_service_obj->getDeductionRatio($dis_pay_money, $store_score_deduction[$params['store_id']]);//积分抵扣比例 }else{ $deduction_ratio = 0; } } $temp_dis_pay_money = $dis_pay_money; $deduct_money = 0; $deduct_num_score = self::scoreDeduction($params['mall_id'], $params['user_id'], $deduction_ratio, $dis_pay_money, $deduct_money,$deduct['score']['is_can_use']); $deduct['score']['money'] = -$deduct_money; $deduct['score']['name'] = $score_name; $deduct['score']['deduct_val'] = $deduct_num_score; if (empty($params['is_use_score'])) { $dis_pay_money = $temp_dis_pay_money; } } $marketing['deduct'] = $deduct; $pay_money = $dis_pay_money; list($total_credit_money,$credit_rate) = self::getCredit($params['store_id'],$pay_money); //赊账 $marketing['credit'] = ['name' => '赊账', 'total_credit_money' => $total_credit_money,'total_credit_rate'=>$credit_rate.'%']; if(!empty($params['is_use_credit'])) $pay_money = bcsub($pay_money,$total_credit_money,2); $pay_money = bcmul($pay_money,1,2); return ['pay_money' => $pay_money, 'marketing' => $marketing]; } //获取赊账信息 protected static function getCredit($store_id,$pay_money){ $store = Store::findOne(['id'=>$store_id]); $credit_money = $credit_rate = 0; if(!empty($store['is_open_credit'])){ $extra = StoreCashierExtra::findOne(['store_id'=>$store_id]); if(!empty($extra['credit_rate'])){ $credit_rate = $extra['credit_rate']; $credit_money = bcdiv($pay_money*$credit_rate,100,2); } } return [$credit_money,$credit_rate]; } //获取能使用的优惠券 protected static function getCanUseCouponList($user_id, $extra,$pay_money) { $list = []; if (!empty($extra['preferential_deduction'])) { $score_deduct_setting = json_decode($extra['score_deduct_setting'], true); switch ($score_deduct_setting['type']) { case 1: case 2: $coupon_id = $score_deduct_setting['coupon_id']; $cond = [ 'where' => [ ['coupon_id' => $coupon_id], ['user_id' => $user_id], ['status' => StatusEnum::ENABLED], ['is_giving' => 0], ['is_force_failure' => 0], ['is_use' => 0], ['<=', 'start_time', time()], ['>=', 'end_time', time()], ['coupon_status' => 2], ['giving_status' => [0, 1]], ], 'select' => 'id', ]; $coupon = AddonsCoupon::getOne([['id' => $coupon_id],['<=','min_price',$pay_money]], true); $user_coupon_list = StoreCouponUserRelate::lists($cond); if ($user_coupon_list && $coupon) { foreach ($user_coupon_list as $item) { $coupon['user_coupon_id'] = $item['id']; $list[] = $coupon; } } break; case 3: break; } } return $list; } //计算使用优惠券后的金额 protected static function useCouponDiscount($user_id, $user_coupon_id, $pay_money, &$dis_pay_money, &$deduct_money) { if (!empty($user_coupon_id)) { $cond = [ ['id' => $user_coupon_id], ['user_id' => $user_id], ['status' => StatusEnum::ENABLED], ['is_giving' => 0], ['is_force_failure' => 0], ['is_use' => 0], ['<=', 'start_time', time()], ['>=', 'end_time', time()], ['coupon_status' => 2], ['giving_status' => [0, 1]], ]; $user_coupon = StoreCouponUserRelate::getOne($cond); if (!empty($user_coupon)) { $coupon = AddonsCoupon::getOne([['id' => $user_coupon['coupon_id']]], true); if ($coupon) { if (!empty($coupon['is_original_use']) && $pay_money != $dis_pay_money) throw new Exception('原价支付才能使用优惠券:' . $coupon['name']); //最低消费 if (!empty($coupon['min_price']) && $dis_pay_money < $coupon['min_price']) throw new Exception('没有达到最低支付金额'); //折扣 if ($coupon['type'] == AddonsCouponEnum::DISCOUNT) { $discount = sprintf('%.2f', $dis_pay_money * $coupon['discount'] / 10); //折扣 if ($coupon['discount_limit'] != '0.00' && $discount > $coupon['discount_limit']) { $discount = $coupon['discount_limit']; } if ($dis_pay_money > $discount) { $deduct_money = $dis_pay_money - $discount; $dis_pay_money -= $discount; } else { $deduct_money = $dis_pay_money; $dis_pay_money = 0; } } //满减 if ($coupon['type'] == AddonsCouponEnum::FULL_MINUS) { $sub_price = $coupon['sub_price']; if ($dis_pay_money > $sub_price) { $deduct_money = $sub_price; $dis_pay_money -= $sub_price; } else { $deduct_money = $dis_pay_money; $dis_pay_money = 0; } } } } } } protected static function useScoreDiscount($mall_id, $user_id, $extra, &$dis_pay_money, &$deduct_money) { $deduct_num_score = 0; if (!empty($extra['preferential_deduction'])) { $score_deduct_setting = json_decode($extra['score_deduct_setting'], true); switch ($score_deduct_setting['type']) { case 1: case 2: break; case 3: $deduct_type = $score_deduct_setting['score_deduct']['deduct_type']; $deduct_num = $score_deduct_setting['score_deduct']['deduct_num']; if ($deduct_type == 2) $deduct_num = $dis_pay_money * $deduct_num / 100; $user_score = UserWallet::getOne([['user_id' => $user_id]], false, [], false, 'score'); if ($user_score->score < $deduct_num) { $deduct_num = $user_score->score; } //计算积分==多少元 $deduct_setting = \Yii::$app->services->setting->mall->get($mall_id, 'score'); //金额需要的积分数量 $max_num = bcmul($dis_pay_money, $deduct_setting['score_deduct_ratio'], 2); if ($deduct_num > $max_num) $deduct_num = $max_num; $exc_money = 0; !empty($deduct_setting['score_deduct_ratio']) && $exc_money = bcdiv($deduct_num, $deduct_setting['score_deduct_ratio'], 2); if ($dis_pay_money > $exc_money) { $dis_pay_money -= $exc_money; $deduct_money += $exc_money; } else { $deduct_money += $dis_pay_money; $dis_pay_money = 0; } $deduct_num_score = $deduct_num; break; } } return $deduct_num_score; } protected static function scoreDeduction($mall_id, $user_id,$deduction_ratio, &$dis_pay_money, &$deduct_money,&$is_can_use=0) { $platform_basic_score_deduction = \Yii::$app->services->setting->addons->get($mall_id, StoreEnum::ADDONS_NAME, 'payment.score_deduction'); $platform_basic_score_deduction = json_decode($platform_basic_score_deduction, true); $score_balance_ratio = $platform_basic_score_deduction['score_balance_ratio'];//N积分抵1元 if(empty($score_balance_ratio)){ return 0; } $exc_money = bcmul($dis_pay_money, $deduction_ratio / 100, 2); $deduct_num = bcmul($exc_money,$score_balance_ratio,2); $user_score = UserWallet::getOne([['user_id' => $user_id]], false, [], false, 'score'); if($user_score['score']==0){ $is_can_use = 0; return 0; } if ($user_score['score'] < $deduct_num) { //积分不足的情况 $deduct_num = $user_score['score']; $exc_money = bcdiv($deduct_num, $score_balance_ratio , 2); } $temp_money = bcdiv($deduct_num, $score_balance_ratio, 2);//会员积分能抵扣多少元 $dis_pay_money = bcsub($dis_pay_money,$exc_money,2); $deduct_money = $temp_money; $deduct_money > 0 && $deduct_num > 0 && $is_can_use = 1; return $deduct_num; } //扫码后请求 public static function scanCode($params) { try { $add_user_data = [ 'mall_id' => $params['mall_id'], 'user_id' => $params['user_id'], 'store_id' => $params['store_id'], ]; $res = StoreUser:: setData($add_user_data); if ($res == false) throw new \Exception('添加店铺会员失败'); $store = Store::getOne([['id' => $params['store_id']]]); if (empty($params['user']['parent_id']) && !empty($store['scan_code_bind'])) { $user_id = $params['user_id']; $parent_id = $store['user_id']; $param = [ 'user_id' => $user_id, 'parent_id' => $parent_id, ]; $parent = User::getOne([['id' => $parent_id]]); $user = $params['user']; if($user['id']!=$parent_id){ $parent_id_arr = UserPartitionRelationship::getParentIdArr($store['user_id']); if(!in_array($user['id'],$parent_id_arr)){ $user->parent_id = $parent_id; $user->second_parent_id = $parent['parent_id'] ?? 0; $user->third_parent_id = $parent['second_parent_id'] ?? 0; $res = $user->save(); if ($res === false) throw new $user->getErrorMessage(); // $res = UserPartitionRelationship::setData($param); $param['is_admin'] = 0; $param['ip'] = ArrayHelper::get_client_ip(); $param['operator_user_id'] = $param['user_id']; $res = \Yii::$app->services->rabbitMq->push(RabbitMqEnum::EXCHANGE_TASK_CHANGE_RELATIONSHIP, RabbitMqEnum::CHANGE_RELATIONSHIP_QUEUE, $param, UserPartitionRelationship::class, 'changeRelationship'); if ($res === false) throw new \PHPUnit\Util\Exception(UserPartitionRelationship::getStaticError()); } } } $marketing = []; $extra = StoreCashierExtra::findOne(['mall_id' => $params['mall_id'], 'store_id' => $params['store_id']]); $deduct = []; if (!empty($extra['preferential_deduction'])) { $score_deduct_setting = json_decode($extra['score_deduct_setting'], true); $deduct['score']['is_can_use'] = 0; $deduct['score']['name'] = '积分抵扣'; $deduct['coupon']['is_can_use'] = 0; $deduct['coupon']['name'] = '优惠券抵扣'; switch ($score_deduct_setting['type']) { case 1: case 2: $deduct['coupon']['is_can_use'] = 1; $coupon_list = self::getCanUseCouponList( $params['user_id'], $extra,0); $deduct['coupon']['list'] = $coupon_list; break; case 3: $deduct['score']['is_can_use'] = 1; break; } } $setting = StoreSettings::getOne([['mall_id' => $params['mall_id']], ['store_id' => $params['store_id']], ['status' => StatusEnum::ENABLED]], false, [], false, 'cashier_goods_complete_direct,cashier_is_open_discount'); $cashier_goods_complete_direct = $setting['cashier_goods_complete_direct'] ?? 0; $cashier_is_open_discount = $setting['cashier_is_open_discount'] ?? 0; $marketing['deduct'] = $deduct; $advertising = \Yii::$app->services->setting->addons->get($params['mall_id'], StoreEnum::ADDONS_NAME, 'advertising'); if(!isset($advertising)){ $advertising= ['is_open'=>0, 'pic'=>'', 'url'=>'']; } return ['id' => $store['id'], 'store_name' => $store['store_name'], 'logo_img' => $store['logo_img'],'marketing'=>$marketing, 'cashier_goods_complete_direct' => $cashier_goods_complete_direct, 'cashier_is_open_discount'=>$cashier_is_open_discount, 'advertising' => $advertising]; } catch (\Exception $e) { self::$static_error = $e->getMessage(); return false; } } //生成收银台订单 public static function createOrder($params) { $t = Yii::$app->db->beginTransaction(); try { $extra = StoreCashierExtra::getOne([['mall_id' => $params['mall_id']], ['store_id' => $params['store_id']]],true); $dis_pay_money = $params['money']; $extra_desc = []; $user_coupon_id = 0; $cashier = \Yii::$app->services->setting->addons->get($params['mall_id'], StoreEnum::ADDONS_NAME, 'cashier'); $members = []; if(!empty($cashier['member_status'])){ $members = json_decode($cashier['members'], true); } $deduct_money = 0; $store_setting = StoreSettings::findOne(['mall_id' => $params['mall_id'], 'store_id' => $params['store_id'],'status'=>StatusEnum::ENABLED]); if(!empty($store_setting['cashier_member_status'])){ $members = json_decode($store_setting['cashier_member_settings'], true); } if(!empty($members)&&is_array($members)){ $members = array_column($members,null,'level'); } list($member_deduct_money,$discount) = self::computeMemberPrice($members,$dis_pay_money,$params['user']['level']); if (!empty($params['user_coupon_id']) && !empty($extra['preferential_deduction'])) { self::useCouponDiscount($params['user_id'], $params['user_coupon_id'], $params['money'], $dis_pay_money, $deduct_money); if($deduct_money>0){ $user_coupon_id = $params['user_coupon_id']; $extra_desc['discount_money'] = $deduct_money; $extra_desc['user_coupon_id'] = $user_coupon_id; } } $deduct_num_score = 0; if (!empty($params['is_use_score'])) { $platform_basic_score_deduction = \Yii::$app->services->setting->addons->get($params['mall_id'], StoreEnum::ADDONS_NAME, 'payment.score_deduction'); $platform_basic_score_deduction = is_array($platform_basic_score_deduction) ? $platform_basic_score_deduction : json_decode($platform_basic_score_deduction, true); $store_settings_row = StoreSettings::getOne([['mall_id' => $params['mall_id']], ['store_id' => $params['store_id']], ['status' => StatusEnum::ENABLED]], true); !empty($store_settings_row['score_deduction']) && $store_setting = json_decode($store_settings_row['score_deduction'], true); $effective = !empty($store_setting['is_alone_score_deduction']) && !empty($store_setting['effective']) ? $store_setting['effective'] : $platform_basic_score_deduction['effective']; if (!empty($platform_basic_score_deduction['is_score_deduction']) && !empty($platform_basic_score_deduction['score_balance_ratio']) && !empty($store_setting['is_score_deduction']) && $effective != 3) { if (!empty($platform_basic_score_deduction['deduction_type'])) { // 判断平台是否为门店设置了最高抵扣比例,没有则走全局的 $deduction_ratio = !empty($platform_basic_score_deduction['store_limit_type']) && isset($platform_basic_score_deduction['store_limit_stores_deduction'][$params['store_id']]) && is_numeric($platform_basic_score_deduction['store_limit_stores_deduction'][$params['store_id']]) ? $platform_basic_score_deduction['store_limit_stores_deduction'][$params['store_id']] : $platform_basic_score_deduction['max_deduction_percent']; // 判断门店独立设置最高抵扣比例 isset($store_setting) && isset($store_setting['max_deduction_percent']) && !empty($store_setting['is_alone_score_deduction']) && is_numeric($store_setting['max_deduction_percent']) && $deduction_ratio = $store_setting['max_deduction_percent']; }else{ $store_setting_service_obj = (new StoreSettingService(['mall_id' => $params['mall_id']])); $store_score_deduction = $store_setting_service_obj->getDeductionProportion(['store_id' => [$params['store_id']], 'order_type' => 'store_cashier_order']); if (!empty($store_score_deduction[$params['store_id']])){ $deduction_ratio = $store_setting_service_obj->getDeductionRatio($dis_pay_money, $store_score_deduction[$params['store_id']]);//积分抵扣比例 }else{ $deduction_ratio = 0; } } $deduct_num_score = self::scoreDeduction($params['mall_id'], $params['user_id'], $deduction_ratio, $dis_pay_money, $deduct_money); if($deduct_money>0){ $extra_desc['discount_money'] = $deduct_money; $extra_desc['deduct_num_score'] = $deduct_num_score; } } } if (isset($params['user_card_id']) && !empty($params['user_card_id']) && !empty($params['user_card_money'])) { $deduct_money = 0; $members_card_obj = new \addons\MembersCard\common\logic\order\MemberCardMarketing(); $members_card_obj::storeCashierCompute($params['mall_id'],$params['user_id'], $params['user_card_id'], $dis_pay_money, $deduct_money,$params['user_card_money']); if($deduct_money > 0){ $extra_desc['user_card_id'] = [ 'card_give_id' => $params['user_card_id'], 'deduct_money' => $deduct_money, 'user_card_money' => $params['user_card_money'], ]; } } $extra_desc['member_deduct_money'] = $member_deduct_money; $extra_desc['discount'] = $discount; $extra_desc['user_level'] = $params['user']['level']; $params['pay_money'] = $dis_pay_money; $service_money = self:: computeServiceFee($params); $params['amount_received'] = $params['money'] - $service_money; $params['service_money'] = $service_money; $params['order_no'] = StringHelper::generateOrderNo('C'); $store = Store::findOne(['id'=>$params['store_id']]); $give_score_num = self::computeGiveScore($params['mall_id'],$params['store_id'],$store['user_id'],$dis_pay_money,$deduct_num_score); $extra_desc['give_score'] = $give_score_num; if (!empty($extra_desc)) $params['extra'] = json_encode($extra_desc); $store_cashier_order = self::setData($params); if ($store_cashier_order == false) throw new \Exception(self::getStaticError()); // 处理收银台商品商品 if(isset($params['attr_ids']) && !empty($params['attr_ids'])){ StoreCashierOrderDetail::batchDataSave($params['attr_ids'], [ 'cashier_order_id' => $store_cashier_order['id'], 'user_id' => $params['user_id'], 'mall_id' => $params['mall_id'], 'store_id' => $params['store_id'], 'pay_money' => $params['pay_money'] ]); } $pay_money = $params['pay_money']; //赊账 if(!empty($params['is_use_credit'])){ $store = Store::findOne(['id'=>$params['store_id']]); if(!empty($store['is_open_credit'])) { list($total_credit_money, $credit_rate) = self::getCredit($params['store_id'], $params['pay_money']); if (!empty($total_credit_money)) { $params['pay_money'] = bcsub($params['pay_money'], $total_credit_money, 2); $param = [ 'mall_id' => $store_cashier_order['mall_id'], 'user_id' => $store_cashier_order['user_id'], 'order_id' => $store_cashier_order['id'], 'store_id' => $store_cashier_order['store_id'], 'type' => 2, 'is_repayment' => 0, 'down_payments' => $params['pay_money'], 'credit_money' => $total_credit_money, ]; $res = StoreOrderCredit::setData($param); if ($res === false) throw new \Exception(StoreOrderCredit::getStaticError()); } } } $order_trade_info[] = [ 'order_no' => $params['order_no'], 'amount' => $params['pay_money'], 'title' => $params['title'], 'notify_class' => 'addons\Store\common\logic\notify\CashierNotify', 'order_type' => 'cashier_order', ]; //生成支付流水 $res = \Yii::$app->services->pay->createTrade($params['mall_id'], $params['user_id'], $order_trade_info); if ($res == false) throw new \Exception('生成支付流水失败'); $arr['transaction'] = $res; $arr['pay_success_page'] = \Yii::$app->services->setting->addons->get($params['mall_id'], StoreEnum::ADDONS_NAME, 'payment.pay_after_link');//支付成功后跳转的地址 // 判断是否有安装抽奖插件 if (MallAddons::isInstall($params['mall_id'], AddonsEnum::ADDONS_NAME_SHOPPING_LOTTERY)) { $arr['pay_success_page'] = LotteryHelper::getJumpUrl($params['mall_id'], $res['trade_no'], StatusEnum::ENABLED); } $payment_expire_time = Yii::$app->services->setting->mall->get($params['mall_id'], 'order.payment_expire_time'); $arr['surplus_second'] = 30 * 60; //剩余秒数 if ($payment_expire_time) { $arr['surplus_second'] = intval($payment_expire_time) * 60; //剩余秒数 } if(!empty($user_coupon_id)){ $res = StoreCouponUserRelate::updateAll(['is_use'=>1], ['id' => $user_coupon_id]); if($res === false) throw new Exception(AddonsCouponUserRelate::getStaticError()); } if (!empty($params['is_use_score'])&&!empty($deduct_num_score)) { self::subUserScore($params,$store_cashier_order,$deduct_num_score); } if($give_score_num>0){ try { self::subStoreUserScore($params['mall_id'],$store_cashier_order,$store['user_id'],$give_score_num); }catch (Exception $e){ $extra_desc['give_score'] = 0; $store_cashier_order->extra == json_encode($extra_desc); $store_cashier_order->save(); Yii::error('store_cashier_order_id:'.$store_cashier_order['id'].$e->getMessage()); } } $t->commit(); return $arr; } catch (\Exception $e) { $t->rollBack(); self::$static_error = $e->getMessage(); return false; } } //计算会员价,优惠金额 public static function computeMemberPrice($members,&$money,$level) { $discount = 0; $discount_money = 0; if(!empty($members[$level])){ $discount = $members[$level]['discount']; } if ($discount) $discount_money = bcdiv($money * $discount,100,2); $money = bcsub($money,$discount_money,2); if($money<0) $money = 0; return [$discount_money,$discount]; } //计算服务费 public static function computeServiceFee($params) { $store_settings = StoreSettings::getOne([['store_id' => $params['store_id'], 'status' => StatusEnum::ENABLED]]); if (!empty($store_settings['cachier_service_ratio'])) { $service_fee_ratio = $store_settings['cachier_service_ratio']; } else { $service_fee_ratio = \Yii::$app->services->setting->addons->get($params['mall_id'], StoreEnum::ADDONS_NAME, 'cashier.service_fee_ratio'); } $service_money = 0; if ($service_fee_ratio) { $service_money =bcdiv($params['pay_money'] * $service_fee_ratio,100,2); } return $service_money; } //支付收银台订单 public static function pay($params) { try { $trans = Yii::$app->db->beginTransaction(); $model = self::findOne(['id' => $params['id'], 'status' => [StatusEnum::ENABLED]]); if (empty($model)) throw new \Exception('订单不存在或已删除'); if ($model->pay_status != OrderStatusEnum::NOT_PAY) throw new Exception('订单已经被处理,无法进行支付'); if ($model->pay_status == StatusEnum::ENABLED) throw new Exception('订单已支付,请不要重复支付'); $model->payment_type = $params['pay_type']; $model->pay_status = StatusEnum::ENABLED; $model->pay_time = time(); $res = $model->save(); if ($res === false) throw new Exception('修改订单失败:' . $model->getErrorMessage()); StoreOrderCredit::updateAll(['pay_time'=>time()],['order_id'=>$params['id'],'type'=>2]); StoreCashierOrderDetail::updateAll(['order_status' => OrderStatusEnum::ACCOMPLISH], ['cashier_order_id' => $model['id'], 'order_status' => OrderStatusEnum::NOT_PAY]); $trans->commit(); // 触发订单支付事件,事务提交完成后触发 $event = new CashierOrderPaidEvent($model['mall_id']); $order['id'] = $model['id']; $order['operator_id'] = $params['operator_id'] ?? 0; $order['operator_name'] = $params['operator_name'] ?? ''; Yii::$app->services->events->dispatch($event, $order, $event->listeners); return $model; } catch (Exception $e) { if (isset($trans)) $trans->rollback(); self::$static_error = $e->getMessage(); return false; } } /** * 取消订单 * @Author bing * @DateTime 2021-09-14 15:43:18 * @copyright: Copyright (c) 2020 广东七件事集团 * @param [type] $params * @return StoreCashierOrder */ public static function close($params,$force = false){ $trans = Yii::$app->db->beginTransaction(); try{ $cond = ['mall_id' => $params['mall_id'],'status'=>[StatusEnum::ENABLED]]; if(isset($params['id'])){ $cond['id'] = $params['id']; }else{ $cond['order_no'] = $params['order_no']; } isset($params['user_id']) && $cond['user_id'] = $params['user_id']; $model = self::findOne($cond); if(empty($model)) throw new Exception('订单不存在或已删除'); // 判断订单是否已经被关闭 if ($model->status == StatusEnum::DELETE) throw new Exception('订单已经关闭'); // 判断是否是未支付的订单 if ($force == false && $model->pay_status != OrderStatusEnum::NOT_PAY) throw new Exception('订单已经被处理'); $model->status = StatusEnum::DELETE; if (!$model->save()) throw new Exception($model->getErrorMessage()); $extra = json_decode($model['extra'],true); //退回优惠券 if(!empty($extra['user_coupon_id'])){ $res = AddonsCouponUserRelate::updateAll(['is_use'=>0], ['id' => $extra['user_coupon_id']]); if ($res==false) throw new Exception(AddonsCouponUserRelate::getStaticError()); } $goods_ids_stock = []; $order_details = StoreCashierOrderDetail::findAll(['cashier_order_id' => $model['id'], 'order_status' => OrderStatusEnum::NOT_PAY]); /** @var StoreCashierOrderDetail $detail */ foreach($order_details as $detail) { $detail->order_status = OrderStatusEnum::REPEAL; if(!$detail->save()){ throw new \Exception($detail->getErrorMessage()); } $result = StoreGoodsAttr::handleStock($detail['goods_attr_id'], $detail['num']); if ($result === false) { throw new \Exception(StoreGoodsAttr::getStaticError()); } $goods_ids_stock[$detail['goods_id']] = $detail['goods_id']; } foreach($goods_ids_stock as $goods_id){ $stock = StoreGoodsAttr::find()->where(['goods_id'=>$goods_id])->sum('stock'); $stock= $stock??0; $res = StoreGoods::updateAll(['stock'=>$stock],['id'=>$goods_id]); if(!$res) throw new \Exception(StoreGoods::getStaticError()); } $trans->commit(); self::backStoreUserScore($model); if($extra['deduct_num_score']>0){ self::backUserScore($model,$extra['deduct_num_score']); } return $model; }catch(Exception $e){ $trans->rollback(); // 解锁 self::$static_error = $e->getMessage(); return false; } } /** * 计算赠送的积分 * @param $mall_id * @param $pay_money * @param $deduct_num_score * @return int|string */ protected static function computeGiveScore($mall_id,$store_id,$store_user_id,$pay_money,$deduct_num_score) { $give_score_num = 0; $score_give_config = \Yii::$app->services->setting->addons->get($mall_id, StoreEnum::ADDONS_NAME, 'scoreGive'); if (empty($score_give_config['score_give_setting'])) { return $give_score_num; } $score_give_setting = json_decode($score_give_config['score_give_setting'], true);//基础配置 if(empty($score_give_setting['is_open'])){ return $give_score_num; } $bear = $score_give_setting['bear'] ?? 0; if ($bear == 1) { $user_wallet = UserWallet::findOne(['user_id'=>$store_user_id]); } // 判断门店是否有“积分赠送”权限限制 if (!empty($score_give_config['store_limit_type']) && isset($score_give_config['store_limit_stores'])) { $store_limit_stores = json_decode($score_give_config['store_limit_stores'], true); if (!in_array($store_id, $store_limit_stores)) { return $give_score_num; } } try { $condition = $score_give_setting['condition']; $give_type = $score_give_setting['give_type']; $give_num = $score_give_setting['give_num']; if ($bear == 1) { $store_setting = StoreSettings::getOne( [ ['mall_id' => $mall_id], ['store_id' => $store_id], ['status' => StatusEnum::ENABLED] ],true,[],false,'score_give'); if(!empty($store_setting)){ $store_setting = json_decode($store_setting['score_give'],true); if(!empty($store_setting)&& !empty($store_setting['is_alone_score_give'])){ $condition = $store_setting['condition']; $give_type = $store_setting['give_type']; $give_num = $store_setting['give_num']; } } } if($condition==1 && $deduct_num_score>0){//未使用积分抵扣的订单 return $give_score_num; } if($give_type==2){//百分比 $give_num = $pay_money * $give_num/100 ; } if ($bear == 1 ) { //判断门店主的积分 if(empty($user_wallet)){ $give_num = 0; }elseif($give_num > $user_wallet['score']){ $give_num = $user_wallet['score']; } } }catch (Exception $e){ $give_num = 0; } if($give_num>0){ $give_score_num += $give_num; } return bcadd($give_score_num,0,2); } /** * 积分赠送-扣除门店主积分 * @param $mall_id * @param $score_give_data * @return void * @throws Exception */ protected static function subStoreUserScore($mall_id,$order,$store_user_id,$give_score) { $score_give_setting = \Yii::$app->services->setting->addons->get($mall_id, StoreEnum::ADDONS_NAME, 'scoreGive.score_give_setting'); $score_give_setting = json_decode($score_give_setting,true);//基础配置 $bear = $score_give_setting['bear'] ?? 0; if ($bear != 1) { return true; } $prize_name = '积分赠送'; $desc = '门店承担门店收银台订单(' . $order['order_no'] . ')奖励,奖励类型:' . $prize_name . ',积分:' . $give_score; $data = [ 'mall_id' =>$mall_id, 'user_id' => $store_user_id, 'is_frozen' => false, 'wallet_type' => 'score', 'money' => -$give_score, 'desc' => $desc, 'source_table' => StoreCashierOrder::tableName(), 'source_table_id' => $order['id'], 'from_type' => AddonsEnum::ADDONS_NAME_STORE, 'capital_type' => UserWalletEnum::CONSUME_ORDER_GIVE, 'order_no' =>$order['order_no'], ]; $res = UserWalletService::handle(0, $data); if ($res == false) throw new \Exception('积分赠送扣除门店主积分失败'); } /** * 积分抵扣-扣减用户积分 * @param $params * @param $order_id * @param $deduct_num_score * @return void * @throws Exception */ protected static function subUserScore($params,$order,$deduct_num_score) { $desc = '用户('.$params['user_id'].'),下单(收银台订单)('.$order['order_no'].')抵扣积分,数量:'.$deduct_num_score; $data = [ 'message_id' => 0, 'not_add_total' => true, 'mall_id' => $params['mall_id'], 'user_id' => $params['user_id'], 'is_frozen' => false, 'wallet_type' => 'score', 'money' => -$deduct_num_score, 'desc' => $desc, 'source_table' => StoreCashierOrder::tableName(), 'source_table_id' => $order['id'], 'from_type' => AddonsEnum::ADDONS_NAME_STORE, 'capital_type' => UserWalletEnum::STORE_CASHIER_ORDER_CREATE, 'order_no' => $order['order_no'], ]; $res = UserWalletService::handle(0, $data); if ($res == false) throw new \Exception('抵扣积分失败'); } /** * 订单关闭-退回积分赠送给门店主 * @param $order * @return true|void * @throws Exception */ protected static function backStoreUserScore($order) { $store = Store::findOne(['id'=>$order['store_id']]); $store_user_id = $store['user_id']??0; if($store_user_id==0){ return true; } $score_log_list = ScoreLog::lists([ 'where'=>[ ['user_id'=>$store_user_id], ['change_type'=>'sub'], ['source_table' => StoreCashierOrder::tableName()], ['source_table_id'=>$order['id']], ['from_type' => AddonsEnum::ADDONS_NAME_STORE], ['capital_type'=>UserWalletEnum::CONSUME_ORDER_GIVE], ] ]); if(!empty($score_log_list)){ $prize_name = '订单关闭-退回积分赠送'; $insert_wallet = []; foreach ($score_log_list as $item){ $score = $item['change_num']; $desc = '订单关闭,退回积分赠送扣除门店主的积分,门店收银台订单(' . $order['order_no'] . '),类型:' . $prize_name . ',积分:' . $score; $insert_wallet[] = [ 'mall_id' => $item['mall_id'], 'user_id' => $item['user_id'], 'is_frozen' => false, 'wallet_type' => 'score', 'money' => $score, 'desc' => $desc, 'source_table' => StoreCashierOrder::tableName(), 'source_table_id'=>$order['id'], 'from_type' => AddonsEnum::ADDONS_NAME_STORE, 'capital_type' => UserWalletEnum::CONSUME_ORDER_GIVE, 'order_no' =>$order['order_no'], ]; } $res = UserWalletService::batchHandleByQueue($insert_wallet); } } /** * 订单关闭-退回积分抵扣积分 * @param $order * @return true|void * @throws Exception */ protected static function backUserScore($order,$deduct_num_score) { $desc = '用户('.$order['user_id'].'),(收银台订单关闭)('.$order['order_no'].')退回积分,数量:'.$deduct_num_score; $insert_wallet[] = [ 'message_id' => 0, 'not_add_total' => true, 'mall_id' => $order['mall_id'], 'user_id' => $order['user_id'], 'is_frozen' => false, 'wallet_type' => 'score', 'money' => $deduct_num_score, 'desc' => $desc, 'source_table' => StoreCashierOrder::tableName(), 'source_table_id' => $order['id'], 'from_type' => AddonsEnum::ADDONS_NAME_STORE, 'capital_type' => UserWalletEnum::STORE_CASHIER_ORDER_CLOSE, 'order_no' =>$order['order_no'], ]; $res = UserWalletService::batchHandleByQueue($insert_wallet); } /** * 收银台订单-退款-贵九汇客户站点需要手动退款,使用 * @param $order_no * @return bool|string */ public function refund($order_no) { $trans = Yii::$app->db->beginTransaction(); try { $order = StoreCashierOrder::findOne(['order_no' => $order_no,'status'=>StatusEnum::ENABLED]); if (empty($order)) throw new Exception("收银台订单不存在或已删除"); $mallId = $order['mall_id']; $refund_price = $order->pay_money; if (empty($refund_price)) { return true; } $refund_order_no = Order::generateOrderNo('c_r'); // 操作退款-退货退款,仅退款 $insert_wallet = []; //重置写入钱包数据 $orderUserId = $order->user_id; $refundUserId = $order->user_id; //是否为组合支付 $payment_trade_order = PaymentTradeOrder::findOne(['order_no' => $order['order_no'], 'is_pay' => OrderStatusEnum::PAY]); if (empty($payment_trade_order)) { return '支付流水订单不存在'; } $payment_trade = PaymentTrade::findOne(['id' => $payment_trade_order['trade_id']]); if (empty($payment_trade)) { return '支付流水不存在'; } if (!empty($payment_trade->is_pay_group)) { $payment_group_trade_list = PaymentTrade::find()->where(['is_pay' => 1, 'is_pay_group' => 1, 'parent_trade_id' => $payment_trade->id])->orderBy('id asc')->all(); } else { $payment_group_trade_list[] = $payment_trade; } $all_refund_price = $order->pay_money; // 类型为后台主动退款时,处理佣金、积分数据 foreach ($payment_group_trade_list as $payment_group_trade) { if ($all_refund_price > $payment_group_trade->pay_fee) { $refund_price = $payment_group_trade->pay_fee; } else { $refund_price = $all_refund_price; } if (in_array($payment_group_trade->pay_type, [PayTypeEnum::BALANCE, PayTypeEnum::SCORE])) { // 本地支付 $wallet_type = $payment_group_trade->pay_type == PayTypeEnum::SCORE ? UserWalletService::WALLET_TYPE_SCORE : UserWalletService::WALLET_TYPE_BALANCE; $extra_refund_price = 0;//额外抵扣金额 if ($wallet_type == UserWalletService::WALLET_TYPE_BALANCE) { //判断是否有卡券插件 if (MallAddons::isInstall($mallId, AddonsEnum::ADDONS_NAME_CARD_COUPONS)) { $card_refund_price = $order->pay_money - $payment_group_trade->pay_fee; $extra_refund_price = CardCouponsScoreGive::setOrderRefund([ 'refund_price' => $card_refund_price, 'trade_id' => $payment_group_trade->id, 'refund_id' => $order->id ]); } } $insert_wallet[] = [ 'mall_id' => $mallId, 'user_id' => $refundUserId, 'is_frozen' => false, 'wallet_type' => $wallet_type,// 暂定退回余额或积分 'money' => $refund_price, 'desc' => '收银台订单退款-订单(' . $order->id . ')', 'source_table' => StoreCashierOrder::tableName(), 'source_table_id' => $order->id, 'from_type' => UserWalletEnum::REFUND, 'capital_type' => UserWalletEnum::REFUND_ORDER, 'order_no' => $order->order_no, 'not_add_total' => false ]; $refund_price += $extra_refund_price; } elseif (in_array($payment_group_trade->pay_type, [PayTypeEnum::JOINPAY, PayTypeEnum::ALI, PayTypeEnum::JOINPAY_FAST_PAY, PayTypeEnum::WECHAT, PayTypeEnum::SANDPAY_FAST_PAY])) { //原路返回 $originUserId = $order->user_id; $order->user_id = $orderUserId; $res = Yii::$app->services->pay->refund($order->pay_money, $refund_price, $payment_group_trade->out_trade_no, $order, '收银台订单退款'); $order->user_id = $originUserId; if ($res === false) throw new \Exception('退款失败'); } elseif ($order->payment_type == PayTypeEnum::OFFLINE) { // 此支付方式为后台管理员直接支付不做任何处理 } elseif ( // 当res返回为false 说明没有相对于的退款方式 $res = GlobalInvoke::exec(GlobalInvoke::INVOKE_ORDER_REFUND, $mallId, [ 'id' => $order->id, 'mall_id' => $mallId, 'refund' => [], 'params' => [], 'order_no' => $order['order_no'], 'refund_order_no' => $refund_order_no, 'payment_trade_id' => $payment_group_trade->id, 'refund_price' => $refund_price, 'pay_type' => $order->payment_type, ]) ) { // 当res不为空 进此判断 list($boolean, $msg) = $res; if ($boolean === false) { $this->setError($msg); return false; } } $all_refund_price = bcsub($all_refund_price, $refund_price, 2); if ($all_refund_price <= 0) break; } $store = Store::findOne(['id'=>$order['store_id']]); if($store->balance){ $store->balance = bcsub($store->balance,$order->pay_money,2); if($store->balance<0){ $store->balance = 0; } $store->save(); } $order->status = -1; $order->save(); StoreCommission::updateAll(['status'=>StatusEnum::DELETE],['order_no'=>$order['order_no']]); $trans->commit(); $extra= json_decode($order['extra'],true); if(!empty($extra['deduct_num_score'])){ $insert_wallet[] = [ 'mall_id' => $mallId, 'user_id' => $refundUserId, 'is_frozen' => false, 'wallet_type' => 'score',// 暂定退回余额或积分 'money' => $extra['deduct_num_score'], 'desc' => '收银台订单退款-订单(' . $order->id . '),退回抵扣的积分', 'source_table' => StoreCashierOrder::tableName(), 'source_table_id' => $order->id, 'from_type' => UserWalletEnum::REFUND, 'capital_type' => UserWalletEnum::REFUND_ORDER, 'order_no' => $order->order_no, ]; } if(!empty($extra['give_score'])){ $insert_wallet[] = [ 'mall_id' => $mallId, 'user_id' => $refundUserId, 'is_frozen' => false, 'wallet_type' => 'score',// 暂定退回余额或积分 'money' => -$extra['give_score'], 'desc' => '收银台订单退款-订单(' . $order->id . '),扣除赠送的积分', 'source_table' => StoreCashierOrder::tableName(), 'source_table_id' => $order->id, 'from_type' => UserWalletEnum::REFUND, 'capital_type' => UserWalletEnum::REFUND_ORDER, 'order_no' => $order->order_no, ]; } if (!empty($insert_wallet)) { $res = UserWalletService::batchHandleByQueue($insert_wallet); if (empty($res)) throw new \Exception(UserWalletService::getStaticError()); } return true; } catch (Exception $e) { $trans->rollBack(); $this->setError($e->getMessage()); return false; } } }