571 lines
18 KiB
PHP
Executable File
571 lines
18 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* @createtime 2023/4/26
|
|
* @author wild
|
|
* @copyright PhpStorm
|
|
*/
|
|
|
|
|
|
namespace App\Service;
|
|
|
|
|
|
use App\Enums\BoolEnum;
|
|
use App\Enums\LottState;
|
|
use App\Enums\LottType;
|
|
use App\Enums\OrderType;
|
|
use App\Enums\PayState;
|
|
use App\Enums\SaleState;
|
|
use App\Exceptions\JingCaiException;
|
|
use App\Model\Config;
|
|
use App\Model\Customer\Customer;
|
|
use App\Model\Lottery;
|
|
use App\Model\LotteryType;
|
|
use App\Model\Order;
|
|
use App\Model\OrderCtzqJqcResult;
|
|
use App\Model\Seller\Seller;
|
|
use App\Model\Zq\CtzqJqc;
|
|
use App\Model\Zq\CtzqJqcMatch;
|
|
use App\Utils\Helps;
|
|
use App\Utils\ThrowException;
|
|
use Illuminate\Support\Arr;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class CtzqJqcService implements IJingcai
|
|
{
|
|
use JingCaiTrait;
|
|
|
|
public function getOddsFromRequestData($odds) {
|
|
$result = [];
|
|
foreach ($odds as $k => $items) {
|
|
foreach ($items as $team => $item) {
|
|
$result[$k][$team] = array_keys($item);
|
|
}
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* 可销售的彩票赔率
|
|
* @param Customer $customer
|
|
* @return mixed
|
|
*/
|
|
public function saleLotteries(Customer $customer, $lotteryTypeId)
|
|
{
|
|
$lotteryType = LotteryType::where('type', LottType::CTZQ_JQC)
|
|
->where('status', BoolEnum::YES)
|
|
->find($lotteryTypeId);
|
|
ThrowException::isTrue(!$lotteryType, '不支持此彩种');
|
|
|
|
/** @var Lottery $lottery */
|
|
$lottery = Lottery::active()
|
|
->shopAndType($customer->shop_id, $lotteryTypeId)
|
|
->first();
|
|
ThrowException::isTrue(!$lottery, '店铺不支持此彩种');
|
|
|
|
|
|
$ctzqs = CtzqJqc::with('matches')
|
|
->where('state', SaleState::Selling)
|
|
->orderBy('issue_num', 'asc')
|
|
->get();
|
|
$playTypes = LotteryType::select([
|
|
'name',
|
|
DB::raw('type as play_type'),
|
|
DB::raw('id as lottery_type_id'),
|
|
])
|
|
->where('status', BoolEnum::YES)
|
|
->whereIn('type', [LottType::CTZQ_BQC, LottType::CTZQ_JQC])
|
|
->get()->toArray();
|
|
$result = [
|
|
'play_types' => $playTypes,
|
|
'odds' => []
|
|
];
|
|
|
|
$odds = [];
|
|
/** @var $ctzqs $ctzq */
|
|
foreach ($ctzqs as $ctzq) {
|
|
if (!$ctzq->matches || count($ctzq->matches) < 1) {
|
|
continue;
|
|
}
|
|
foreach ($ctzq->matches as $mat) {
|
|
$mat->match_time_date = date('Y-m-d', strtotime($mat->match->start_time));
|
|
$mat->match_time_hour = date('H:i', strtotime($mat->match->start_time)) . '开赛';
|
|
}
|
|
$ctzq->close_time = $ctzq->getCloseTime($lottery->earlySecond());
|
|
$odds[] = $ctzq;
|
|
}
|
|
$result['odds'] = $odds;
|
|
return $result;
|
|
}
|
|
|
|
public function valid(Lottery $lottery, $data)
|
|
{
|
|
$oddsData = Arr::get($data, 'odds');
|
|
|
|
$ctzqMatchId = array_key_first($oddsData);
|
|
|
|
$ctzqMatch = CtzqJqcMatch::find($ctzqMatchId);
|
|
ThrowException::isTrue(!$ctzqMatch, '无对应的比赛数据,无法投注');
|
|
$ctzq = CtzqJqc::where('id', $ctzqMatch->ctzq_jqc_id)->first();
|
|
ThrowException::isTrue(!$ctzq, '无此期投注');
|
|
ThrowException::isTrue($ctzq->state != SaleState::Selling, '不在销售中');
|
|
|
|
if (date('Y-m-d H:i:s') > $ctzq->getCloseTime($lottery->earlySecond())) {
|
|
ThrowException::run( '已截止投注');
|
|
}
|
|
$oddsData = Arr::get($data, 'odds');
|
|
|
|
ThrowException::isTrue(count($oddsData) != 4, '请选择全部4场比赛主队和客队总进球数进行投注');
|
|
|
|
$ids = array_keys($oddsData);
|
|
$countIds = CtzqJqcMatch::where('ctzq_jqc_id', $ctzq->id)
|
|
->whereIn('id', $ids)->count();
|
|
ThrowException::isTrue($countIds != count($ids), '选择的比赛数据有误');
|
|
|
|
foreach ($oddsData as $id => $odd) {
|
|
$homeOdds = Arr::get($odd, 'home_odds', []);
|
|
$awayOdds = Arr::get($odd, 'away_odds', []);
|
|
|
|
if (count($homeOdds) <= 0 || count($awayOdds) <= 0) {
|
|
ThrowException::run('请选择全部4场比赛主队和客队总进球数进行投注');
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* 计算价格
|
|
* @param $data 数据
|
|
* @param $betsNum 倍数
|
|
* @return mixed
|
|
*/
|
|
public function computePrizeInfo($data, $betsNum = 1, $mnKeys = [])
|
|
{
|
|
$input = $this->getCombinationInput($data);
|
|
$combinationData = Helps::getCombinationData($input, count($data));
|
|
$zhuNum = count($combinationData);
|
|
return [
|
|
'money' => $zhuNum * $betsNum * Config::lotteryUnitPrice(),
|
|
'zhu_num' => $zhuNum,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 获取二维数组组合的入参
|
|
* @param $data {1=>[1,2], ..}
|
|
*/
|
|
public function getCombinationInput($data)
|
|
{
|
|
$result = [];
|
|
foreach ($data as $id => $odds) {
|
|
$item = [];
|
|
$home = $odds['home_odds'];
|
|
$away = $odds['away_odds'];
|
|
foreach ($home as $homeScore) {
|
|
foreach ($away as $awayScore) {
|
|
$item[] = $this->generateCtzqCombinationItem($id, $homeScore, $awayScore);
|
|
}
|
|
}
|
|
|
|
$result[] = $item;
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
public function generateCtzqCombinationItem($id, $homeScore, $awayScore)
|
|
{
|
|
return sprintf('%d-%s-%s', $id, $homeScore, $awayScore);
|
|
}
|
|
|
|
public function parserCtzqCombinationItem($item)
|
|
{
|
|
$arr = explode('-', $item);
|
|
return [
|
|
'ctzq_match_id' => $arr[0],
|
|
'home_score' => $arr[1],
|
|
'away_score' => $arr[2],
|
|
];
|
|
}
|
|
|
|
|
|
/**
|
|
* 刷新数据的赔率
|
|
* @param $data
|
|
* @return mixed
|
|
*/
|
|
public function refreshOdds($data)
|
|
{
|
|
return $data;
|
|
}
|
|
|
|
public function createPiaos($oddsData, $betsNum)
|
|
{
|
|
$input = $this->getCombinationInput($oddsData);
|
|
$combinationData = Helps::getCombinationData($input, count($oddsData));
|
|
|
|
$data = [];
|
|
foreach ($combinationData as $comBitem) {
|
|
$dataItem = [];
|
|
foreach ($comBitem as $item) {
|
|
$itemInfo = $this->parserCtzqCombinationItem($item);
|
|
$dataItem[] = $itemInfo['home_score'] ;
|
|
$dataItem[] = $itemInfo['away_score'];
|
|
}
|
|
$itemKey = implode('|',$dataItem);
|
|
$data[$itemKey] = $betsNum;
|
|
}
|
|
|
|
$piaos = [];
|
|
$this->addPiaos($piaos, $data);
|
|
return $piaos;
|
|
}
|
|
|
|
public function addPiaos(&$piaos, $arr)
|
|
{
|
|
$remainArr = [];
|
|
$num = 0;
|
|
$piao = [];
|
|
$ok = false;
|
|
$maxNum = Config::piaoMaxBetsNum();
|
|
foreach ($arr as $k => $val) {
|
|
$tempNum = $num + $val;
|
|
if (!$ok) {
|
|
if ($tempNum >= $maxNum) {
|
|
$ying = $maxNum - $num;
|
|
$num += $ying;
|
|
$piao[$k] = $ying;
|
|
|
|
$ok = true;
|
|
if ($val - $ying > 0) {
|
|
$remainArr[$k] = $val - $ying;
|
|
}
|
|
continue;
|
|
}
|
|
$num += $val;
|
|
$piao[$k] = $val;
|
|
} else {
|
|
$remainArr[$k] = $val;
|
|
}
|
|
}
|
|
$piaos[] = $piao;
|
|
if ($remainArr) {
|
|
$this->addPiaos($piaos, $remainArr);
|
|
}
|
|
}
|
|
/**
|
|
* 创建订单
|
|
* @param Customer $customer
|
|
* @param $data
|
|
* @return Order
|
|
*/
|
|
public function createOrder(Customer $customer, $data)
|
|
{
|
|
$lotteryTypeId = Arr::get($data, 'lottery_type_id');
|
|
$type = Arr::get($data, 'type', OrderType::NORMAL);
|
|
$fadanSecret = Arr::get($data, 'type_mode', 1);
|
|
$fadanDesc = Arr::get($data, 'type_desc', '');
|
|
$betsNum = Arr::get($data, 'bets_num');
|
|
|
|
$oddsData = Arr::get($data, 'odds'); // 购买的场次或投注信息
|
|
$union_piece_total = intval(Arr::get($data, 'union_piece_total', 0));
|
|
$union_piece_buy = intval(Arr::get($data, 'union_piece_buy', 0));
|
|
$union_piece_keep = intval(Arr::get($data, 'union_piece_keep', 0));
|
|
$union_keep = Arr::get($data, 'union_keep', BoolEnum::NO);
|
|
$union_brokerage = intval(Arr::get($data, 'union_brokerage', 0));
|
|
|
|
ThrowException::isTrue($type == OrderType::FADAN, '该彩种不支持发单');
|
|
ThrowException::isTrue($type == OrderType::GENDAN, '该彩种不支持跟单');
|
|
|
|
/** @var Lottery $lott */
|
|
$lott = LotteryService::getLottery($customer->shop->id, $lotteryTypeId);
|
|
ThrowException::isTrue(!$lott, '店铺未开通该彩种');
|
|
|
|
$this->valid($lott, $data);
|
|
|
|
$computeInfo = $this->computePrizeInfo($oddsData, $betsNum);
|
|
$lott->validMixMoney($computeInfo['money']);
|
|
if ($type == OrderType::UNION) {
|
|
$lott->validEnableHemai();
|
|
throw_if(!$fadanDesc, JingCaiException::create('请填写合买宣言!'));
|
|
ThrowException::isTrue($union_piece_total <= 0, '总份数不能小于0');
|
|
|
|
$piecePrice = $computeInfo['money'] / $union_piece_total;
|
|
ThrowException::isTrue($piecePrice <= 1, '每份金额必须大于1');
|
|
|
|
ThrowException::isTrue($union_piece_buy > $union_piece_total, '超过方案总金额');
|
|
if ($union_keep == BoolEnum::YES) {
|
|
$union_piece_keep = $union_piece_total - $union_piece_buy;
|
|
}
|
|
|
|
$this->canCreateUnionOrder($customer->id);
|
|
}
|
|
|
|
$ctzqMatchId = array_key_first($oddsData);
|
|
$ctzqMatch = CtzqJqcMatch::find($ctzqMatchId);
|
|
ThrowException::isTrue(!$ctzqMatch, '无对应的比赛数据,无法投注');
|
|
/** @var \App\Model\Zq\CtzqJqc $ctzq */
|
|
$ctzq = CtzqJqc::where('id', $ctzqMatch->ctzq_jqc_id)->where('state', SaleState::Selling)->first();
|
|
|
|
DB::beginTransaction();
|
|
try {
|
|
|
|
$earlyTime = $ctzq->getCloseTime($lott->earlySecond());
|
|
$lateTime =$ctzq->getCloseTime($lott->earlySecond());
|
|
|
|
$this->checkCloseTimeOver($earlyTime);
|
|
|
|
$piaos = $this->createPiaos($oddsData, $betsNum);
|
|
|
|
$order = new Order();
|
|
$order->pid = 0;
|
|
$order->customer_id = $customer->id;
|
|
$order->lottery_id = $lott->id;
|
|
$order->shop_id = $customer->shop_id;
|
|
$order->lottery_type_id = $lott->lottery_type_id;
|
|
$order->order_sn = Order::makeOrderSn();
|
|
$order->play_type = '';
|
|
$order->bets_num = $betsNum;
|
|
$order->zhu_num = $computeInfo['zhu_num'];
|
|
$order->piao_num = count($piaos);
|
|
$order->money = $computeInfo['money'];
|
|
$order->prize_min = 0;
|
|
$order->prize_max = 0;
|
|
$order->pay_state = PayState::UNPAID;
|
|
$order->pass_mode = [];
|
|
$order->odds_close_time = $ctzq->getCloseTime(0);
|
|
$order->odds_early_close_time = $earlyTime;
|
|
$order->odds_late_close_time = $lateTime;
|
|
$order->type = $type;
|
|
$order->type_mode = $fadanSecret;
|
|
$order->type_desc = $fadanDesc;
|
|
$order->odds = $oddsData;
|
|
if ($type == OrderType::UNION) {
|
|
$pieceMoney = $order->money / $union_piece_total;
|
|
$order->union_piece_total = $union_piece_total;
|
|
$order->union_piece_buy = $union_piece_buy;
|
|
$order->union_piece_self = $union_piece_buy;
|
|
$order->union_piece_keep = $union_piece_keep;
|
|
$order->union_keep = $union_keep;
|
|
$order->union_brokerage = $union_brokerage;
|
|
$order->union_piece_money = $pieceMoney;
|
|
$order->union_money = $pieceMoney * ($union_piece_buy + $union_piece_keep);
|
|
}
|
|
$order->created_date = date('Ymd');
|
|
// 设置合作相关的数据
|
|
$order->setCooperateInfo($lott);
|
|
$order->save();
|
|
|
|
// 如果是合买,更新自己的pid
|
|
if ($order->type == OrderType::UNION) {
|
|
$order->pid = $order->id;
|
|
$order->save();
|
|
}
|
|
|
|
// 创建组合数据
|
|
// $this->createZuhe($betsInfos, $order->id);
|
|
$ids = array_keys($oddsData);
|
|
$matches = CtzqJqcMatch::where('ctzq_jqc_id', $ctzq->id)
|
|
->whereIn('id', $ids)->get()->keyBy('id');
|
|
$orderOdds = [];
|
|
foreach ($oddsData as $ctzqMatchId => $info) {
|
|
|
|
$match = Arr::get($matches, $ctzqMatchId);
|
|
$orderOdds[] = [
|
|
'order_id' => $order->id,
|
|
'ctzq_jqc_id' => $ctzq->id,
|
|
'ctzq_jqc_match_id' => $ctzqMatchId,
|
|
'match_id' => $match->match_id,
|
|
'home_odds' => json_encode($info['home_odds'], JSON_UNESCAPED_UNICODE),
|
|
'away_odds' => json_encode($info['away_odds'], JSON_UNESCAPED_UNICODE),
|
|
'created_at' => date('Y-m-d H:i:s'),
|
|
'updated_at' => date('Y-m-d H:i:s'),
|
|
];
|
|
}
|
|
OrderCtzqJqcResult::insert($orderOdds);
|
|
|
|
DB::commit();
|
|
return $order;
|
|
} catch (JingCaiException $e) {
|
|
DB::rollBack();
|
|
Log::error('ctzq::order::create ValidateException: ' . $e);
|
|
throw $e;
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
Log::error('ctzq::order::create Exception: ' . $e);
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 跟单
|
|
* @param Customer $customer
|
|
* @param Order $order
|
|
* @param $data
|
|
* @return Order
|
|
*/
|
|
public function copyOrder(Customer $customer, Order $order, $data)
|
|
{
|
|
|
|
}
|
|
|
|
/**
|
|
* 展示订单详情
|
|
* @param Customer $customer 查看订单的人
|
|
* @param Order $order
|
|
* @return mixed
|
|
*/
|
|
public function showOrder(Customer $customer, Order $order)
|
|
{
|
|
$order->sellings = [];
|
|
// 自购的
|
|
if ($order->customerCanSeeSellings($customer)) {
|
|
$this->setOrderOdds($order);
|
|
}
|
|
|
|
$order->chang_num = count($order->sellings);
|
|
|
|
$order->play_name = $order->lottery->name;
|
|
|
|
unset($order->lottery);
|
|
|
|
return $order;
|
|
}
|
|
|
|
private function setOrderOdds(Order $order) {
|
|
|
|
$oddsData = $order->odds;
|
|
$ctzqMatchs = CtzqJqcMatch::whereIn('id', array_keys($oddsData))->get();
|
|
$ctzqMatch = Arr::get($ctzqMatchs, 0);
|
|
$ctzq = CtzqJqc::find($ctzqMatch->ctzq_jqc_id);
|
|
$matchs = $ctzq->matchs;
|
|
|
|
$matchKeys = $ctzqMatchs->keyBy('match_id');
|
|
|
|
$nos = [];
|
|
$teams = [];
|
|
$results = [];
|
|
$scores0 = [];
|
|
$scores1 = [];
|
|
$scores2 = [];
|
|
$scores3 = [];
|
|
|
|
foreach ($matchs as $item) {
|
|
|
|
$nos[$item['no']] = $item['no'];
|
|
if ($item['no'] % 2 == 0) {
|
|
$fieldName = 'away_odds';
|
|
$teamNameField = 'jcAwayTeamName';
|
|
} else {
|
|
$fieldName = 'home_odds';
|
|
$teamNameField = 'jcHomeTeamName';
|
|
}
|
|
|
|
$matchKey = Arr::get($matchKeys, $item['matchId']);
|
|
|
|
$matchScore = Arr::get($oddsData, $matchKey->id. '.' . $fieldName);
|
|
if ($matchScore !== null) {
|
|
$score0 = in_array('0', $matchScore) ? '0' : '';
|
|
$score1 = in_array('1', $matchScore) ? '1' : '';
|
|
$score2 = in_array('2', $matchScore) ? '2' : '';
|
|
$score3 = in_array('3+', $matchScore) ? '3+' : '';
|
|
|
|
$scores0[$item['no']] = $score0;
|
|
$scores1[$item['no']] = $score1;
|
|
$scores2[$item['no']] = $score2;
|
|
$scores3[$item['no']] = $score3;
|
|
}
|
|
|
|
|
|
$teams[$item['no']] = $item[$teamNameField];
|
|
$results[$item['no']] = $item['result'];
|
|
}
|
|
|
|
$scores = [
|
|
$nos,
|
|
$teams,
|
|
$scores0,
|
|
$scores1,
|
|
$scores2,
|
|
$scores3,
|
|
];
|
|
|
|
if ($ctzq->result_info) {
|
|
$scores[] = $results;
|
|
}
|
|
|
|
$order->sellings = $scores;
|
|
$order->issue_num = $ctzq->issue_num;
|
|
return $order;
|
|
}
|
|
|
|
|
|
/**
|
|
* 店主-展示订单详情
|
|
* @param Seller $seller 查看订单的人
|
|
* @param Order $order
|
|
* @return mixed
|
|
*/
|
|
public function sellerShowOrder(Seller $seller, Order $order)
|
|
{
|
|
$order->sellings = [];
|
|
if ($order->sellerCanSeeSellings($seller)) {
|
|
$this->setOrderOdds($order);
|
|
}
|
|
$order->chang_num = count($order->sellings);
|
|
$order->play_name = $order->lottery->name;
|
|
|
|
unset($order->lottery);
|
|
|
|
return $order;
|
|
}
|
|
|
|
public function chaiPiao(Order $order)
|
|
{
|
|
$piaos = $this->createPiaos($order->odds, $order->bets_num);
|
|
|
|
$header = [
|
|
[
|
|
'prop' => 'index',
|
|
'title' => '编号',
|
|
],
|
|
[
|
|
'prop' => 'type',
|
|
'title' => '过关',
|
|
],
|
|
[
|
|
'prop' => 'play_name',
|
|
'title' => '投注内容',
|
|
],
|
|
[
|
|
'prop' => 'nums',
|
|
'title' => '倍数/票数',
|
|
],
|
|
[
|
|
'prop' => 'money',
|
|
'title' => '金额',
|
|
],
|
|
];
|
|
$piaoList = [];
|
|
foreach ($piaos as $k => $piaoData) {
|
|
|
|
$buyOdds = [
|
|
];
|
|
$piaoBetNum = 0;
|
|
foreach ($piaoData as $odd => $betNum) {
|
|
$piaoBetNum+= $betNum;
|
|
$buyOdds[] = $odd;
|
|
}
|
|
$piaoList[] = [
|
|
'header' => $header,
|
|
'data' => [
|
|
'index' => $k +1 ,
|
|
'type' => '单式',
|
|
'play_name' => $buyOdds,
|
|
'nums' => sprintf('%d倍/%d张', $order->bets_num, 1),
|
|
'money' => $piaoBetNum * $order->bets_num * Config::lotteryUnitPrice()
|
|
],
|
|
'summary' => '',
|
|
];
|
|
}
|
|
return $piaoList;
|
|
}
|
|
}
|