1715 lines
62 KiB
PHP
Executable File
1715 lines
62 KiB
PHP
Executable File
<?php
|
||
|
||
namespace App\Service;
|
||
|
||
use App\Enums\BoolEnum;
|
||
use App\Enums\LottState;
|
||
use App\Enums\LottType;
|
||
use App\Enums\OptimizeType;
|
||
use App\Enums\OrderType;
|
||
use App\Enums\PayState;
|
||
use App\Enums\PlayType;
|
||
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\OrderJczqResult;
|
||
use App\Model\OrderZuhe;
|
||
use App\Model\Seller\Seller;
|
||
use App\Model\Zq\JczqOdds;
|
||
use App\Model\Zq\JczqResult;
|
||
use App\Utils\Helps;
|
||
use App\Utils\ThrowException;
|
||
use Illuminate\Support\Arr;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Log;
|
||
|
||
class JczqService implements IJingcai
|
||
{
|
||
use JingCaiTrait;
|
||
|
||
/** @var PlayTypeService playTypeService */
|
||
protected $playTypeService;
|
||
|
||
public function __construct()
|
||
{
|
||
$this->playTypeService = app(PlayTypeService::class);
|
||
}
|
||
|
||
public function playTypeNames()
|
||
{
|
||
return [
|
||
'bf_odds' => '全场比分',
|
||
'jq_odds' => '总进球',
|
||
'bqc_odds' => '半全场胜平负',
|
||
'spf_odds' => '胜平负',
|
||
'rq_odds' => '让球胜平负',
|
||
];
|
||
}
|
||
|
||
public function getPlayTypeName($playType)
|
||
{
|
||
$fieldNames = $this->playTypeNames();
|
||
$result = $fieldNames[$playType];
|
||
return $result;
|
||
}
|
||
|
||
public function resultFieldNames()
|
||
{
|
||
return [
|
||
// 胜平负
|
||
'single' => '单关',
|
||
'win' => '胜',
|
||
'draw' => '平',
|
||
'loss' => '负',
|
||
'handicap' => '让球数',
|
||
// 比分
|
||
'wh1a0' => '1:0',
|
||
'wh2a0' => '2:0',
|
||
'wh2a1' => '2:1',
|
||
'wh3a0' => '3:0',
|
||
'wh3a1' => '3:1',
|
||
'wh3a2' => '3:2',
|
||
'wh4a0' => '4:0',
|
||
'wh4a1' => '4:1',
|
||
'wh4a2' => '4:2',
|
||
'wh5a0' => '5:0',
|
||
'wh5a1' => '5:1',
|
||
'wh5a2' => '5:2',
|
||
'wx' => '胜其他',
|
||
'dh0a0' => '0:0',
|
||
'dh1a1' => '1:1',
|
||
'dh2a2' => '2:2',
|
||
'dh3a3' => '3:3',
|
||
'dx' => '平其他',
|
||
'lh0a1' => '0:1',
|
||
'lh0a2' => '0:2',
|
||
'lh1a2' => '1:2',
|
||
'lh0a3' => '0:3',
|
||
'lh1a3' => '1:3',
|
||
'lh2a3' => '2:3',
|
||
'lh0a4' => '0:4',
|
||
'lh1a4' => '1:4',
|
||
'lh2a4' => '2:4',
|
||
'lh0a5' => '0:5',
|
||
'lh1a5' => '1:5',
|
||
'lh2a5' => '2:5',
|
||
'lx' => '负其他',
|
||
|
||
// 半全场
|
||
'ww' => '胜胜',
|
||
'wd' => '胜平',
|
||
'wl' => '胜负',
|
||
'dw' => '平胜',
|
||
'dd' => '平平',
|
||
'dl' => '平负',
|
||
'lw' => '负胜',
|
||
'ld' => '负平',
|
||
'll' => '负负',
|
||
|
||
// 进球数
|
||
'g0' => '0',
|
||
'g1' => '1',
|
||
'g2' => '2',
|
||
'g3' => '3',
|
||
'g4' => '4',
|
||
'g5' => '5',
|
||
'g6' => '6',
|
||
'g7m' => '7',
|
||
];
|
||
}
|
||
|
||
public static function inWinFields($playType, $field)
|
||
{
|
||
$fields = self::winFields($playType);
|
||
return in_array($field, $fields);
|
||
}
|
||
public static function winFields($playType)
|
||
{
|
||
if ($playType == PlayType::RQ || $playType == PlayType::SPF) {
|
||
return ['win'];
|
||
}
|
||
if ($playType == PlayType::BF) {
|
||
return [
|
||
'wh1a0',
|
||
'wh2a0',
|
||
'wh2a1',
|
||
'wh3a0',
|
||
'wh3a1',
|
||
'wh3a2',
|
||
'wh4a0',
|
||
'wh4a1',
|
||
'wh4a2',
|
||
'wh5a0',
|
||
'wh5a1',
|
||
'wh5a2',
|
||
'wx' ,
|
||
];
|
||
}
|
||
if ($playType == PlayType::JQ) {
|
||
return [ 'g1' , 'g2' , 'g3' , 'g4' ,'g5' ,'g6' ,'g7m',];
|
||
}
|
||
if ($playType == PlayType::BQC) {
|
||
return ['ww', 'wd', 'wl'];
|
||
}
|
||
return [];
|
||
}
|
||
|
||
public static function inDrawFields($playType, $field)
|
||
{
|
||
$fields = self::drawFields($playType);
|
||
return in_array($field, $fields);
|
||
}
|
||
public static function drawFields($playType)
|
||
{
|
||
if ($playType == PlayType::RQ || $playType == PlayType::SPF) {
|
||
return ['draw'];
|
||
}
|
||
if ($playType == PlayType::BF) {
|
||
return [
|
||
'dh0a0',
|
||
'dh1a1',
|
||
'dh2a2',
|
||
'dh3a3',
|
||
'dx',
|
||
];
|
||
}
|
||
if ($playType == PlayType::JQ) {
|
||
return ['g0' , 'g2', 'g4' ,'g6',];
|
||
}
|
||
if ($playType == PlayType::BQC) {
|
||
return ['dw', 'dd', 'dl'];
|
||
}
|
||
return [];
|
||
}
|
||
public static function inLossFields($playType, $field)
|
||
{
|
||
$fields = self::lossFields($playType);
|
||
return in_array($field, $fields);
|
||
}
|
||
public static function lossFields($playType)
|
||
{
|
||
if ($playType == PlayType::RQ || $playType == PlayType::SPF) {
|
||
return ['loss'];
|
||
}
|
||
if ($playType == PlayType::BF) {
|
||
return [
|
||
'lh0a1',
|
||
'lh0a2',
|
||
'lh1a2',
|
||
'lh0a3',
|
||
'lh1a3',
|
||
'lh2a3',
|
||
'lh0a4',
|
||
'lh1a4',
|
||
'lh2a4',
|
||
'lh0a5',
|
||
'lh1a5',
|
||
'lh2a5',
|
||
'lx',
|
||
];
|
||
}
|
||
if ($playType == PlayType::JQ) {
|
||
return [ 'g1' , 'g2' , 'g3' , 'g4' ,'g5' ,'g6' ,'g7m',];
|
||
}
|
||
if ($playType == PlayType::BQC) {
|
||
return ['lw', 'ld', 'll'];
|
||
}
|
||
return [];
|
||
}
|
||
|
||
|
||
public function maxPrizeSpliceWdlOdds($matchOdds, $rqHandicap = null)
|
||
{
|
||
$winArray = [];
|
||
$drawArray = [];
|
||
$lossArray = [];
|
||
|
||
foreach ($matchOdds as $playType => $playData) {
|
||
|
||
foreach ($playData as $field => $odds) {
|
||
|
||
if ($playType == PlayType::RQ) {
|
||
$rqNum = $rqHandicap;
|
||
if ($rqHandicap === null) {
|
||
continue;
|
||
}
|
||
if ($rqNum == 1) {
|
||
if ( $field == 'win') {
|
||
$winArray[PlayType::RQ][$field] = $odds;
|
||
$drawArray[PlayType::RQ][$field] = $odds;
|
||
}
|
||
if ( $field == 'draw') {
|
||
$lossArray[PlayType::RQ][$field] = $odds;
|
||
}
|
||
if ($field == 'loss') {
|
||
$lossArray[PlayType::RQ][$field] = $odds;
|
||
}
|
||
} else if($rqNum >= 2) {
|
||
if ($field == 'win') {
|
||
$winArray['rq_odds'][$field] = $odds;
|
||
$drawArray['rq_odds'][$field] = $odds;
|
||
$lossArray['rq_odds'][$field] = $odds;
|
||
}
|
||
if ( $field == 'draw') {
|
||
$lossArray['rq_odds'][$field] = $odds;
|
||
}
|
||
if ( $field == 'loss') {
|
||
$lossArray['rq_odds'][$field] = $odds;
|
||
}
|
||
} else if($rqNum == -1) {
|
||
if ($field == 'win') {
|
||
$winArray['rq_odds'][$field] = $odds;
|
||
}
|
||
if ( $field == 'draw') {
|
||
$winArray['rq_odds'][$field] = $odds;
|
||
}
|
||
if ( $field == 'loss') {
|
||
$drawArray['rq_odds'][$field] = $odds;
|
||
|
||
$lossArray['rq_odds'][$field] = $odds;
|
||
}
|
||
} else if($rqNum <= -2) {
|
||
if ($field == 'win') {
|
||
$winArray['rq_odds'][$field] = $odds;
|
||
}
|
||
if ( $field == 'draw') {
|
||
$winArray['rq_odds'][$field] = $odds;
|
||
}
|
||
if ( $field == 'loss') {
|
||
$winArray['rq_odds'][$field] = $odds;
|
||
$drawArray['rq_odds'][$field] = $odds;
|
||
$lossArray['rq_odds'][$field] = $odds;
|
||
}
|
||
}
|
||
} else {
|
||
if (JczqService::inWinFields($playType, $field)) {
|
||
$winArray[$playType][$field] = $odds;
|
||
}
|
||
if (JczqService::inLossFields($playType, $field)) {
|
||
$lossArray[$playType][$field] = $odds;
|
||
}
|
||
if (JczqService::inDrawFields($playType, $field)) {
|
||
$drawArray[$playType][$field] = $odds;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
foreach ($winArray as $playType => $playData) {
|
||
$winArray[$playType] = $this->maxPrizeSearchMaxOdd($playData);
|
||
}
|
||
foreach ($drawArray as $playType => $playData) {
|
||
$drawArray[$playType] = $this->maxPrizeSearchMaxOdd($playData);
|
||
}
|
||
foreach ($lossArray as $playType => $playData) {
|
||
$lossArray[$playType] = $this->maxPrizeSearchMaxOdd($playData);
|
||
}
|
||
|
||
|
||
|
||
$winOdds = $this->maxPrizeSumPlayOdd($winArray);
|
||
$maxOdds = $winOdds;
|
||
$result = $winArray;
|
||
$drawOdds = $this->maxPrizeSumPlayOdd($drawArray);
|
||
|
||
if ($drawOdds > $maxOdds) {
|
||
$maxOdds = $drawOdds;
|
||
$result = $drawArray;
|
||
}
|
||
$lossOdds = $this->maxPrizeSumPlayOdd($lossArray);
|
||
if ($lossOdds > $maxOdds) {
|
||
$result = $lossArray;
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* @param $oddsData {id => {rf_odds:{win:1.1}}}
|
||
* @param $handicapList {id => 11}
|
||
* @return array
|
||
*/
|
||
public function maxPrizeZuheList($oddsData, $passModes, $handicapList)
|
||
{
|
||
foreach ($oddsData as $id => $matchOddsData) {
|
||
$handicap = Arr::get($handicapList, $id);
|
||
$searchResult = $this->maxPrizeSpliceWdlOdds($matchOddsData, $handicap);
|
||
$result[$id] = $searchResult;
|
||
}
|
||
$zuhes = $this->generateBetsInfo($result,$passModes, 1);
|
||
return $zuhes;
|
||
}
|
||
|
||
/**
|
||
* @param $oddsData {id => {rf_odds:{win:1.1}}}
|
||
* @param $handicapList {id => 11}
|
||
* @return array
|
||
*/
|
||
public function maxPrizeCompute($oddsData,$passModes, $handicapList)
|
||
{
|
||
$zuhes = $this->maxPrizeZuheList($oddsData,$passModes, $handicapList);
|
||
$prize = 0;
|
||
foreach ($zuhes as $zuhe) {
|
||
$prize += $zuhe['all_odds'] * 2;
|
||
}
|
||
return $prize;
|
||
}
|
||
|
||
public function getResultFieldName($playType, $field)
|
||
{
|
||
$fieldNames = $this->resultFieldNames();
|
||
$result = $fieldNames[$field];
|
||
if (!in_array($field, ['win', 'loss', 'draw']) || $playType != 'rq_odds') {
|
||
return $result;
|
||
}
|
||
return '让' . $result;
|
||
}
|
||
public static function generateZqPassModeInfo($oddsData, $playType)
|
||
{
|
||
$matchNum = count($oddsData);
|
||
if ($matchNum == 1) {
|
||
$oddsId = array_key_first($oddsData);
|
||
$jczqOdds = JczqOdds::find($oddsId);
|
||
$oddInfo = $oddsData[$oddsId];
|
||
foreach ($oddInfo as $play =>$v) {
|
||
$info = $jczqOdds->{$play};
|
||
ThrowException::isTrue(!$info, '无此玩法:'.$play);
|
||
ThrowException::isTrue($info['single'] != 1, '该玩法不支持单关'.$play);
|
||
}
|
||
return [
|
||
'multi' => [['key' => '1.1', 'title' => '单关']],
|
||
'single' => []
|
||
];
|
||
}
|
||
|
||
/** @var JczqService $service */
|
||
$service = app(JczqService::class);
|
||
$hasSingle = $service->getSingleOdds($oddsData);
|
||
|
||
|
||
$maxChuan = 8; // 最高8场比赛
|
||
foreach ($oddsData as $item) {
|
||
if (Arr::get($item, PlayType::BF) || Arr::get($item, PlayType::BQC)) {
|
||
if ($maxChuan > 4) {
|
||
$maxChuan = 4;
|
||
}
|
||
}
|
||
if (Arr::get($item, PlayType::JQ)) {
|
||
if ($maxChuan > 6) {
|
||
$maxChuan = 6;
|
||
}
|
||
}
|
||
}
|
||
|
||
$rules = self::passModes();
|
||
$multi = []; // 多选(自由过关)
|
||
$one = []; // 单选(M串N)
|
||
foreach ($rules as $chang => $zhuData) {
|
||
if ($chang == 1) {
|
||
if ($hasSingle) {
|
||
$multi[] = [
|
||
'key' => sprintf('%d.%d', $chang, 1),
|
||
'title' => '单关',
|
||
];
|
||
}
|
||
continue;
|
||
}
|
||
if ($chang > $maxChuan) {
|
||
continue;
|
||
}
|
||
if ($chang > $matchNum) {
|
||
continue;
|
||
}
|
||
foreach ($zhuData as $k => $zhu) {
|
||
$item = [
|
||
'key' => sprintf('%d.%d', $chang, $k),
|
||
'title' => sprintf('%d串%d', $chang, $k),
|
||
];
|
||
|
||
if ($chang <= $matchNum && $k == 1) {
|
||
$multi[] = $item;
|
||
}
|
||
if ($chang == $matchNum && $k >= $matchNum && !isset($zhu[1])) {
|
||
$one[] = $item;
|
||
}
|
||
}
|
||
}
|
||
sort($one);
|
||
return [
|
||
'multi' => $multi,
|
||
'single' => $one
|
||
];
|
||
}
|
||
public function getSingleOdds($oddData) {
|
||
$oddsIds = array_keys($oddData);
|
||
if (!$oddsIds) {
|
||
return [];
|
||
}
|
||
$jclqOdds = JczqOdds::whereIn('id', $oddsIds)->get();
|
||
$result = [];
|
||
|
||
foreach ($jclqOdds as $odd) {
|
||
$oddDataItem = Arr::get($oddData, $odd->id);
|
||
ThrowException::isTrue(!$oddDataItem, '单关比赛不存在');
|
||
foreach ($oddDataItem as $playType => $playData) {
|
||
foreach ($playData as $key => $val) {
|
||
if ($odd->{$playType} === null) {
|
||
Log::error('jczqService:getSingleOdds not found playType', [
|
||
'oddsData' => $oddData,
|
||
'oddDataItem' => $oddDataItem,
|
||
'playType' => $playType,
|
||
'odd' => $odd->toArray(),
|
||
]);
|
||
ThrowException::run('单关数据有误');
|
||
}
|
||
if (Arr::get($odd->{$playType}, 'single') != 1) {
|
||
return [];
|
||
}
|
||
$result[] = [ $this->generateJczqCombinationItem($odd->id, $playType, $key) ];
|
||
}
|
||
}
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
public function saleLotteries(Customer $customer, $lotteryTypeId)
|
||
{
|
||
$lotteryType = LotteryType::where('type', LottType::JCZQ)
|
||
->where('status', BoolEnum::YES)
|
||
->find($lotteryTypeId);
|
||
ThrowException::isTrue(!$lotteryType, '不支持此彩种');
|
||
|
||
/** @var Lottery $lottery */
|
||
$lottery = Lottery::active()
|
||
->shopAndType($customer->shop_id, $lotteryTypeId)
|
||
->first();
|
||
ThrowException::isTrue(!$lotteryType, '店铺不支持此彩种');
|
||
|
||
$odds = JczqOdds::selling()
|
||
->where('real_close_time', '>', date('Y-m-d H:i:s', time() + $lottery->earlySecond()))
|
||
->orderBy('issue_num', 'asc')
|
||
->get();
|
||
|
||
$result = [
|
||
'play_types' => PlayType::asJczqSelectArray(),
|
||
];
|
||
|
||
$competitions = [];
|
||
/** @var JczqOdds $odd */
|
||
foreach ($odds as $odd) {
|
||
|
||
if (!in_array($odd->jc_competition_name, $competitions)) {
|
||
$competitions[] = $odd->jc_competition_name;
|
||
}
|
||
$odd->jc_competition_name = preg_replace('/[0-9]/', '', $odd->jc_competition_name);
|
||
$realCloseTime = strtotime($odd->real_close_time) - $lottery->earlySecond();
|
||
$odd->real_close_time = date('Y-m-d H:i:s', $realCloseTime);
|
||
$odd->real_close_str = date('H:i', $realCloseTime) . '截止';
|
||
$odd->spf_odds = Helps::compareOdds($odd->spf_odds, $odd->spf_odds_last);
|
||
$odd->rq_odds = Helps::compareOdds($odd->rq_odds, $odd->rq_odds_last);
|
||
$odd->bf_odds = Helps::compareOdds($odd->bf_odds, $odd->bf_odds_last);
|
||
$odd->jq_odds = Helps::compareOdds($odd->jq_odds, $odd->jq_odds_last);
|
||
$odd->bqc_odds = Helps::compareOdds($odd->bqc_odds, $odd->bqc_odds_last);
|
||
|
||
JczqOdds::unsetLastSuffixField($odd);
|
||
}
|
||
if ($competitions) {
|
||
array_unshift($competitions, '全部');
|
||
}
|
||
|
||
$result['competitions'] = $competitions;
|
||
$result['odds'] = $odds;
|
||
|
||
return $result;
|
||
}
|
||
|
||
|
||
public function refreshOdds($data)
|
||
{
|
||
$ids = array_keys($data);
|
||
throw_if(!$ids, JingCaiException::create('请选择比赛进行投注'));
|
||
|
||
$odds = JczqOdds::whereIn('id', $ids)->get();
|
||
$odds = collect($odds);
|
||
ThrowException::isTrue($odds->count() != count($ids), '比赛数据错误,请重新选择');
|
||
|
||
$result = [];
|
||
foreach ($data as $id => $val) {
|
||
$item = [];
|
||
foreach ($val as $playType => $playData) {
|
||
$oddItem = $odds->where('id', $id)->first();
|
||
foreach ($playData as $k => $v) {
|
||
$odd = Arr::get($oddItem, $playType . '.' . $k);
|
||
if (!$odd) {
|
||
Log::error('JczqService->refreshOdds数据错误', [
|
||
'data' => $data,
|
||
'key' => $playType . '.' . $k,
|
||
'val' => $odd,
|
||
'id' => $id,
|
||
]);
|
||
}
|
||
|
||
throw_if($odd === null, JingCaiException::create('数据错误,请重新选择'));
|
||
|
||
$item[$playType][$k] = Arr::get($oddItem, $playType . '.' . $k);
|
||
}
|
||
}
|
||
$result[$id] = $item;
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
public function computePrizeInfo($data, $betsNum = 1, $passModeKeys = [])
|
||
{
|
||
return $this->computePrizeInfoV3($data, $betsNum, $passModeKeys);
|
||
sort($passModeKeys);
|
||
$zhuTotal = 0;
|
||
$min = 0;
|
||
$max = 0;
|
||
foreach ($passModeKeys as $key) {
|
||
$passModes = self::getPassMode($key);
|
||
foreach ($passModes as $chang => $changeGe) {
|
||
$prizeInfo = $this->generatePrizeOdds($data, $chang);
|
||
$zhuTotal += $prizeInfo['zhu_num'];
|
||
if (!$min) {
|
||
$min = $prizeInfo['min'];
|
||
}
|
||
if ($prizeInfo['min'] < $min) {
|
||
$min = $prizeInfo['min'];
|
||
}
|
||
$max += $prizeInfo['max'];
|
||
}
|
||
}
|
||
return [
|
||
'zhu_num' => $zhuTotal,
|
||
'expect_bets' => $max,
|
||
'money' => Helps::floatFormat($zhuTotal * $betsNum * Config::lotteryUnitPrice()),
|
||
'prize_min' => Helps::floatFormat($min * $betsNum * Config::lotteryUnitPrice()),
|
||
'prize_max' => Helps::floatFormat($max * $betsNum * Config::lotteryUnitPrice()),
|
||
];
|
||
}
|
||
|
||
public function computePrizeInfoV2($data, $betsNum = 1, $passModeKeys = [])
|
||
{
|
||
sort($passModeKeys);
|
||
$lastKey = array_pop($passModeKeys);
|
||
// 最大的串法
|
||
$betsList = $this->generateBetsInfo($data, [$lastKey], $betsNum);
|
||
|
||
$maxBetsOdd = 0;
|
||
$maxUnique = '';
|
||
foreach ($betsList as $item) {
|
||
if ($item['all_odds'] > $maxBetsOdd) {
|
||
$maxBetsOdd = $item['all_odds'];
|
||
$maxUnique = $item['unique'];
|
||
}
|
||
}
|
||
$allBetsResultUnique = [];
|
||
$allBetsResult = $betsList;
|
||
|
||
$allPrizes = [];
|
||
|
||
$maxUniqueArray = [];
|
||
// 其余串法
|
||
foreach ($betsList as $item) {
|
||
$betItemPrize = $this->getBetsInfoPrize($item);
|
||
|
||
if ($item['unique'] == $maxUnique) {
|
||
$maxUniqueArray[] = $item['unique'];
|
||
}
|
||
@$allBetsResultUnique[$item['unique']] += 1;
|
||
$keyOddsData = $this->betsInfoToOdds($item);
|
||
|
||
foreach ($passModeKeys as $key) {
|
||
$keyBetsData = $this->generateBetsInfo($keyOddsData, [$key], $betsNum);
|
||
|
||
foreach ($keyBetsData as $kitem) {
|
||
@$allBetsResultUnique[$kitem['unique']] += 1;
|
||
$betKItemPrize = $this->getBetsInfoPrize($kitem);
|
||
@$allPrizes[$kitem['unique']] += $betKItemPrize;
|
||
|
||
if ($item['unique'] == $maxUnique) {
|
||
$maxUniqueArray[] = $kitem['unique'];
|
||
}
|
||
}
|
||
$allBetsResult = array_merge($allBetsResult, $keyBetsData);
|
||
}
|
||
$allPrizes[$item['unique']] = $betItemPrize;
|
||
}
|
||
$maxPrize = 0;
|
||
foreach ($allPrizes as $unique => $prize) {
|
||
if (in_array($unique, $maxUniqueArray)) {
|
||
$maxPrize += $prize;
|
||
}
|
||
}
|
||
sort($allPrizes);
|
||
$minPrize = $allPrizes[0];
|
||
|
||
$zhuTotal = count($allBetsResult);
|
||
return [
|
||
'zhu_num' => $zhuTotal,
|
||
'expect_bets' => $maxPrize / $betsNum / Config::lotteryUnitPrice(),
|
||
'money' => Helps::floatFormat($zhuTotal * $betsNum * Config::lotteryUnitPrice()),
|
||
'prize_min' => Helps::floatFormat($minPrize),
|
||
'prize_max' => Helps::floatFormat($maxPrize),
|
||
];
|
||
}
|
||
|
||
public function computePrizeInfoV3($data, $betsNum = 1, $passModeKeys = [])
|
||
{
|
||
$piaos = $this->createPiaoV3($data, $passModeKeys, $betsNum);
|
||
$maxPrize = 0;
|
||
$minPrize = null;
|
||
$maxPrizeIndex = null;
|
||
$allBetsResultUnique = [];
|
||
$zhuTotal = 0;
|
||
foreach ($piaos as $idx => $piao) {
|
||
if ($piao['prize'] > $maxPrize) {
|
||
$maxPrize = $piao['prize'];
|
||
$maxPrizeIndex = $idx;
|
||
}
|
||
foreach ($piao['bets'] as $betsInfo) {
|
||
$zhuTotal += 1;
|
||
@$allBetsResultUnique[$betsInfo['unique']] += 1;
|
||
$betItemPrize = $this->getBetsInfoPrize($betsInfo);
|
||
if (isset($minPrize)) {
|
||
$minPrize = $minPrize < $betItemPrize ? $minPrize : $betItemPrize;
|
||
} else {
|
||
$minPrize = $betItemPrize;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
$jclqOdds = JczqOdds::whereIn('id', array_keys($data))->pluck('rq_odds', 'id')->toArray();
|
||
$handicapList = [];
|
||
foreach ($jclqOdds as $id => $item) {
|
||
if ($item) {
|
||
$handicapList[$id] = $item['handicap'];
|
||
}
|
||
}
|
||
$maxZuheList = $this->maxPrizeZuheList($data, $passModeKeys, $handicapList);
|
||
$maxPrize = 0;
|
||
foreach ($maxZuheList as $zuhe) {
|
||
$repeatNum = $allBetsResultUnique[$zuhe['unique']];
|
||
$maxPrize += $repeatNum * $this->getBetsInfoPrize($zuhe);
|
||
}
|
||
|
||
$maxPrize *= $betsNum;
|
||
|
||
return [
|
||
'zhu_num' => $zhuTotal,
|
||
'expect_bets' => Helps::floatFormat( $maxPrize / $betsNum / Config::lotteryUnitPrice()),
|
||
'money' => Helps::floatFormat($zhuTotal * $betsNum * Config::lotteryUnitPrice()),
|
||
'prize_min' => Helps::floatFormat($minPrize),
|
||
'prize_max' => Helps::floatFormat($maxPrize),
|
||
];
|
||
}
|
||
|
||
|
||
public function generatePrizeOdds($data, $len)
|
||
{
|
||
// 说明是单关
|
||
if ($len == 1) {
|
||
$combinationData = $this->getSingleOdds($data);
|
||
} else {
|
||
$errRes = [
|
||
'zhu_num' => 0,
|
||
'min' => 0,
|
||
'max' => 0,
|
||
];
|
||
$fdata = $this->generateCombinationInput($data);
|
||
if (!$fdata) {
|
||
Log::error('generatePrize格式化数据失败', [
|
||
'data' => $data,
|
||
'len' => $len
|
||
]);
|
||
return $errRes;
|
||
}
|
||
$combinationData = Helps::getCombinationData($fdata, $len);
|
||
if (!$combinationData) {
|
||
Log::error('generatePrize生成组合数据失败', [
|
||
'fdata' => $fdata,
|
||
'len' => $len
|
||
]);
|
||
return $errRes;
|
||
}
|
||
}
|
||
|
||
$prizes = [];
|
||
$zhuTotal = count($combinationData);
|
||
foreach ($combinationData as $keyArr) {
|
||
$keyOdds = 1;
|
||
foreach ($keyArr as $key) {
|
||
$keyInfo = $this->parseJczqCombinationItem($key);
|
||
$baseItemArr = Arr::get($data, $keyInfo['id']);
|
||
$odds = Arr::get($baseItemArr, $keyInfo['play'] . '.' . $keyInfo['result'], null);
|
||
$keyOdds *= $odds;
|
||
}
|
||
$prizes[] = $keyOdds;
|
||
|
||
}
|
||
sort($prizes, SORT_ASC);
|
||
return [
|
||
'zhu_num' => $zhuTotal,
|
||
'min' => $prizes[0],
|
||
'max' => $prizes[count($prizes) - 1],
|
||
];
|
||
}
|
||
|
||
public function generateJczqCombinationItem($id, $playType, $result)
|
||
{
|
||
return sprintf('%d-%s-%s', $id, $playType, $result);
|
||
}
|
||
|
||
public function parseJczqCombinationItem($key)
|
||
{
|
||
$info = explode('-', $key);
|
||
return [
|
||
'id' => $info[0],
|
||
'play' => $info[1],
|
||
'result' => $info[2],
|
||
];
|
||
}
|
||
|
||
public function generateCombinationInput($data, $hasOdds = false)
|
||
{
|
||
$result = [];
|
||
foreach ($data as $id => $item) {
|
||
$resItem = [];
|
||
foreach ($item as $k => $itemData) {
|
||
foreach ($itemData as $kk => $kkv) {
|
||
$resKey = $this->generateJczqCombinationItem($id, $k, $kk);
|
||
if ($hasOdds) {
|
||
$resItem[$resKey] = $kkv;
|
||
} else {
|
||
$resItem[$resKey] = $resKey;
|
||
}
|
||
}
|
||
}
|
||
$result[] = $resItem;
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
public function getBetsInfoFromCombinationData($data, $betsNum = 1, $dataOdd)
|
||
{
|
||
$result = [];
|
||
foreach ($data as $zuheInfo) {
|
||
$resultItem = [];
|
||
$allOdds = 1;
|
||
foreach ($zuheInfo as $key) {
|
||
$keyInfo = $this->parseJczqCombinationItem($key);
|
||
$keyInfo['odd'] = $this->getBetsOddFromCombinationData($key, $dataOdd);
|
||
$allOdds *= $keyInfo['odd'];
|
||
$resultItem['ids'][] = intval($keyInfo['id']);
|
||
$resultItem['keys'][] = $key;
|
||
$resultItem['info'][$keyInfo['id']] = $keyInfo;
|
||
$resultItem['bets_num'] = $betsNum;
|
||
}
|
||
|
||
$tempKeys = $resultItem['keys'];
|
||
sort($tempKeys);
|
||
$resultItem['unique'] = implode(';', $tempKeys);
|
||
$resultItem['all_odds'] = $allOdds;
|
||
$resultItem['chuan_num'] = count($resultItem['ids']);
|
||
|
||
$result[] = $resultItem;
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
public function piaoMatchSame50($piao, $betsInfo)
|
||
{
|
||
|
||
$samePlay = false;
|
||
foreach ($piao['bets'] as $item) {
|
||
if ($item['bets_num'] != Config::piaoMaxBetsNum()) {
|
||
continue;
|
||
}
|
||
$intersectIds = array_intersect($item['ids'], $betsInfo['ids']);
|
||
|
||
|
||
if (count($intersectIds) == count($betsInfo['ids']) &&
|
||
count($intersectIds) == count($item['ids'])) {
|
||
|
||
$samePlay = true;
|
||
foreach ($intersectIds as $id) {
|
||
|
||
if ($item['info'][$id]['play'] == $betsInfo['info'][$id]['play'] &&
|
||
$item['info'][$id]['result'] == $betsInfo['info'][$id]['result']) {
|
||
} else {
|
||
$samePlay = false;
|
||
}
|
||
}
|
||
}
|
||
if ($samePlay) {
|
||
return $samePlay;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
public function piaoMatchCanAddPlay($piao, $betsInfo)
|
||
{
|
||
foreach ($piao['bets'] as $item) {
|
||
$intersectIds = array_intersect($item['ids'], $betsInfo['ids']);
|
||
if ($intersectIds) {
|
||
foreach ($intersectIds as $id) {
|
||
if ($item['info'][$id]['play'] != $betsInfo['info'][$id]['play']) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
public function piaoAddBets(&$piaos, $betsInfo)
|
||
{
|
||
if (count($piaos) == 0) {
|
||
$betsNumAll = $betsInfo['bets_num'];
|
||
// 超出限制,添加一部分,返回剩余的
|
||
if ($betsNumAll > Config::piaoMaxBetsNum()) {
|
||
$addNum = Config::piaoMaxBetsNum();
|
||
$tempBetsInfo = $betsInfo;
|
||
$betsInfo['bets_num'] = $addNum;
|
||
$piaos[0]['bets'][] = $betsInfo;
|
||
$piaos[0]['bets_num'] = $addNum;
|
||
$tempBetsInfo['bets_num'] -= $addNum;
|
||
return $this->piaoAddBets($piaos, $tempBetsInfo);
|
||
}
|
||
|
||
$piaos[0] = [
|
||
'bets' => [$betsInfo],
|
||
'bets_num' => $betsInfo['bets_num']
|
||
];
|
||
$addPiao = true;
|
||
return $addPiao;
|
||
}
|
||
foreach ($piaos as $pk => $piao) {
|
||
// 同一场只能出现一个玩法
|
||
$addPiaoIndex = $pk;
|
||
$tempPiaoIndex = $pk;
|
||
while (true) {
|
||
if ($tempPiaoIndex >= count($piaos)) {
|
||
$addPiaoIndex = count($piaos);
|
||
break;
|
||
}
|
||
$tempPiao = $piaos[$tempPiaoIndex];
|
||
$can = $this->piaoMatchCanAddPlay($tempPiao, $betsInfo);
|
||
if (!$can) {
|
||
$tempPiaoIndex += 1;
|
||
} else {
|
||
if ($this->piaoMatchSame50($tempPiao, $betsInfo)) {
|
||
$tempPiaoIndex += 1;
|
||
} else {
|
||
$addPiaoIndex = $tempPiaoIndex;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
//
|
||
// if (!$can) {
|
||
// $nextPk = count($piaos);
|
||
//
|
||
// $betsNumAll = $betsInfo['bets_num'];
|
||
// // 超出限制,添加一部分,返回剩余的
|
||
// if ($betsNumAll > Config::piaoMaxBetsNum()) {
|
||
// $addNum = Config::piaoMaxBetsNum();
|
||
// $tempBetsInfo = $betsInfo;
|
||
//
|
||
// $betsInfo['bets_num'] = $addNum;
|
||
//
|
||
// $piaos[$nextPk]['bets'][] = $betsInfo;
|
||
// $piaos[$nextPk]['bets_num'] = $addNum;
|
||
//
|
||
// $tempBetsInfo['bets_num'] -= $addNum;
|
||
// return $this->piaoAddBets($piaos, $tempBetsInfo);
|
||
// }
|
||
//
|
||
// $piaos[$nextPk] = [
|
||
// 'bets' => [$betsInfo],
|
||
// 'bets_num' => $betsInfo['bets_num']
|
||
// ];
|
||
// return true;
|
||
// }
|
||
|
||
|
||
$betsNumAll = $betsInfo['bets_num'];
|
||
// 超出限制,添加一部分,返回剩余的
|
||
if ($betsNumAll > Config::piaoMaxBetsNum()) {
|
||
$addNum = Config::piaoMaxBetsNum();
|
||
|
||
|
||
$tempBetsInfo = $betsInfo;
|
||
$betsInfo['bets_num'] = $addNum;
|
||
$piaos[$addPiaoIndex]['bets'][] = $betsInfo;
|
||
@$piaos[$addPiaoIndex]['bets_num'] += $addNum;
|
||
$tempBetsInfo['bets_num'] -= $addNum;
|
||
return $this->piaoAddBets($piaos, $tempBetsInfo);
|
||
}
|
||
|
||
$piaos[$addPiaoIndex]['bets'][] = $betsInfo;
|
||
@$piaos[$addPiaoIndex]['bets_num'] += $betsInfo['bets_num'];
|
||
return true;
|
||
}
|
||
}
|
||
|
||
public function createPiaos($betsInfos)
|
||
{
|
||
$piaoArr = [];
|
||
foreach ($betsInfos as $item) {
|
||
$keyCount = count($item['ids']);
|
||
$piaoArr[$keyCount][] = $item;
|
||
}
|
||
|
||
$piaoResult = [];
|
||
foreach ($piaoArr as $piaoItem) {
|
||
$piaos = [];
|
||
foreach ($piaoItem as $betsInfo) {
|
||
$this->piaoAddBets($piaos, $betsInfo);
|
||
}
|
||
$piaoResult = array_merge($piaoResult, $piaos);
|
||
|
||
}
|
||
return $piaoResult;
|
||
}
|
||
|
||
public function valid(Lottery $lottery, $playType, $data)
|
||
{
|
||
throw_if(count($data) > 8, JingCaiException::create('最多只能选择八场比赛'));
|
||
|
||
$this->playTypeService->validPlayType($playType, $data);
|
||
|
||
if ($lottery->plan_multi == BoolEnum::YES) {
|
||
$allowPlanNum = $lottery->plan_num;
|
||
$this->validZuHe($allowPlanNum, $data);
|
||
}
|
||
|
||
|
||
$odds = [];
|
||
$oneMutilNum = 0;
|
||
foreach ($data as $id => $item) {
|
||
$odds = array_merge($odds, array_keys($item));
|
||
if (count($item) > 1) {
|
||
$oneMutilNum += 1;
|
||
}
|
||
}
|
||
if ($lottery->one_multi == BoolEnum::YES && $oneMutilNum > 1) {
|
||
JingCaiException::throwJingcai("只能选择其中一场比赛进行玩法多选");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 校验组合方案
|
||
*/
|
||
public function validZuHe($allowPlanNum, $data, $combinationLen=2)
|
||
{
|
||
$oddsMatch = $this->generateCombinationInput($data);
|
||
$zuhes = Helps::getCombinationData($oddsMatch, $combinationLen);
|
||
if (count($zuhes) > $allowPlanNum) {
|
||
JingCaiException::throwJingcai("允许的方案组合不超过{$allowPlanNum}个");
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* 根据用户的下注数据,生成购物车中的比赛下注信息
|
||
* @param Array $matchs
|
||
* @return array
|
||
*/
|
||
public function getJczqOddsFromData(Lottery $lottery, $oddsData)
|
||
{
|
||
$jczqCount = JczqOdds::selling()->whereIn('id', array_keys($oddsData))->count();
|
||
throw_if($jczqCount != count($oddsData), JingCaiException::create('比赛信息有误'));
|
||
$odds = JczqOdds::selling()
|
||
->whereIn('id', array_keys($oddsData))
|
||
->orderBy('real_close_time', 'asc')
|
||
->orderBy('play_num', 'asc')
|
||
->get();
|
||
|
||
$result = [];
|
||
foreach ($odds as $odd) {
|
||
|
||
$odd->jc_competition_name = preg_replace('/[0-9]/', '', $odd->jc_competition_name);
|
||
|
||
$realCloseTime = strtotime($odd->real_close_time) - $lottery->earlySecond();
|
||
$odd->real_close_time = date('Y-m-d H:i:s', $realCloseTime);
|
||
$odd->real_close_str = date('H:i', $realCloseTime) . '截止';
|
||
|
||
unset($odd->spf_odds_last);
|
||
unset($odd->rq_odds_last);
|
||
unset($odd->bf_odds_last);
|
||
unset($odd->jq_odds_last);
|
||
unset($odd->bqc_odds_last);
|
||
|
||
|
||
if (@$oddsData[$odd->id]['spf_odds']) {
|
||
$odd->spf_odds = Helps::copyProperty($odd->spf_odds, $oddsData[$odd->id]['spf_odds']);
|
||
} else {
|
||
unset($odd->spf_odds);
|
||
}
|
||
if (@$oddsData[$odd->id]['rq_odds']) {
|
||
$odd->rq_odds = Helps::copyProperty($odd->rq_odds, $oddsData[$odd->id]['rq_odds']);
|
||
} else {
|
||
unset($odd->rq_odds);
|
||
}
|
||
if (@$oddsData[$odd->id]['bf_odds']) {
|
||
$odd->bf_odds = Helps::copyProperty($odd->bf_odds, $oddsData[$odd->id]['bf_odds']);
|
||
} else {
|
||
unset($odd->bf_odds);
|
||
}
|
||
if (@$oddsData[$odd->id]['jq_odds']) {
|
||
$odd->jq_odds = Helps::copyProperty($odd->jq_odds, $oddsData[$odd->id]['jq_odds']);
|
||
} else {
|
||
unset($odd->jq_odds);
|
||
}
|
||
if (@$oddsData[$odd->id]['bqc_odds']) {
|
||
$odd->bqc_odds = Helps::copyProperty($odd->bqc_odds, $oddsData[$odd->id]['bqc_odds']);
|
||
} else {
|
||
unset($odd->bqc_odds);
|
||
}
|
||
$result[] = $odd;
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
public function generateBetsInfo($odds, $passModeKeys, $betsNum)
|
||
{
|
||
$data = $this->generateCombinationInput($odds);
|
||
$result = [];
|
||
foreach ($passModeKeys as $key) {
|
||
$passModes = self::getPassMode($key);
|
||
foreach ($passModes as $chang => $changeGe) {
|
||
if ($chang == 1) {
|
||
$combinationData = $this->getSingleOdds($odds);
|
||
} else {
|
||
$combinationData = Helps::getCombinationData($data, $chang);
|
||
}
|
||
$result = array_merge($result, $combinationData);
|
||
}
|
||
}
|
||
$dataOdd = $this->generateCombinationInput($odds, true);
|
||
return $this->getBetsInfoFromCombinationData($result, $betsNum, $dataOdd);
|
||
}
|
||
|
||
public function createOrder(Customer $customer, $data)
|
||
{
|
||
$optimizeZuhe = Arr::get($data, 'optimize_zuhe');
|
||
$optimizeType = Arr::get($data, 'optimize_type');
|
||
$totalMonay = Arr::get($data, 'money');
|
||
$lotteryTypeId = Arr::get($data, 'lottery_type_id');
|
||
$playType = Arr::get($data, 'play_type');
|
||
$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');
|
||
$passModeKeys = Arr::get($data, 'pass_mode_keys');
|
||
$odds = 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));
|
||
$fadan_order_no = Arr::get($data, 'fadan_order_no', '');
|
||
|
||
if ($optimizeZuhe) {
|
||
$optimizeBetsNumArray = array_column($optimizeZuhe, 'bets_num');
|
||
$allMoney = array_sum($optimizeBetsNumArray) * 2;
|
||
if (Helps::floatFormat($allMoney) != Helps::floatFormat($totalMonay)) {
|
||
ThrowException::run('投注数据有误,请重试!');
|
||
}
|
||
}
|
||
|
||
throw_if(!PlayType::hasValue($playType), JingCaiException::create('无效的玩法!'));
|
||
|
||
/** @var Lottery $lott */
|
||
$lott = LotteryService::getLottery($customer->shop->id, $lotteryTypeId);
|
||
throw_if(!$lott, JingCaiException::create('店铺未开通该彩种!'));
|
||
|
||
$this->valid($lott, $playType, $odds);
|
||
|
||
$odds = $this->refreshOdds($odds);
|
||
|
||
$computeInfo = $this->computePrizeInfo($odds, $betsNum, $passModeKeys);
|
||
|
||
if (!OptimizeType::hasValue($optimizeType)) {
|
||
$optimizeType = 0;
|
||
} else {
|
||
|
||
$computeInfo['prize_max'] = 0;
|
||
$computeInfo['money'] = $totalMonay;
|
||
}
|
||
|
||
$lott->validMixMoney($computeInfo['money']);
|
||
|
||
if ($type == OrderType::FADAN) {
|
||
throw_if(!$fadanDesc, JingCaiException::create('请填写发单宣言!'));
|
||
$this->canCreateFanDanOrder($customer->id);
|
||
ThrowException::isTrue($this->fadanValid($computeInfo['money'], $computeInfo['prize_min']), '最低奖金大于等于投注金额的1.6倍');
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
$pid = 0;
|
||
if ($type == OrderType::GENDAN) {
|
||
$fadanOrder = Order::sn($fadan_order_no)->first();
|
||
ThrowException::isTrue(!$fadanOrder, '所跟订单不存在');
|
||
|
||
ThrowException::isTrue($fadanOrder->lottery_state != LottState::WAIT, '订单状态有误');
|
||
ThrowException::isTrue(date('Y-m-d H:i:s') > $fadanOrder->odds_early_close_time, '所跟订单已结束投注');
|
||
$pid = $fadanOrder->id;
|
||
$fadanSecret = $fadanOrder->type_mode;
|
||
}
|
||
|
||
DB::beginTransaction();
|
||
try {
|
||
|
||
$jczqOdds = JczqOdds::whereIn('id', array_keys($odds))->get();
|
||
$closeTimes = [];
|
||
$oddsCloseTimes = [];
|
||
foreach ($jczqOdds as $match) {
|
||
$realCloseTime = strtotime($match->real_close_time) - $lott->earlySecond();
|
||
$real_close_time = date('Y-m-d H:i:s', $realCloseTime);
|
||
$closeTimes[] = $real_close_time;
|
||
$oddsCloseTimes[] = $match->real_close_time;
|
||
}
|
||
sort($closeTimes);
|
||
sort($oddsCloseTimes);
|
||
$earlyTime = $closeTimes[0];
|
||
$oddsCloseTime = $oddsCloseTimes[0];
|
||
$lateTime = $closeTimes[count($closeTimes) - 1];
|
||
|
||
$this->checkCloseTimeOver($earlyTime);
|
||
|
||
// $betsInfos = $this->generateBetsInfo($odds, $passModeKeys, $betsNum);
|
||
// $piaos = $this->createPiaos($betsInfos);
|
||
$piaos = $this->createPiaosV2($odds, $passModeKeys, $betsNum, $optimizeZuhe);
|
||
$piaoZhang = array_sum(array_column($piaos, 'zhang'));
|
||
$order = new Order();
|
||
$order->pid = $pid;
|
||
$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 = $playType;
|
||
$order->bets_num = $betsNum;
|
||
$order->bets_expect_num = $computeInfo['expect_bets'];
|
||
$order->zhu_num = $computeInfo['zhu_num'];
|
||
$order->piao_num = $piaoZhang;
|
||
$order->money = $computeInfo['money'];
|
||
$order->prize_min = $computeInfo['prize_min'];
|
||
$order->prize_max = $computeInfo['prize_max'];
|
||
$order->pay_state = PayState::UNPAID;
|
||
$order->pass_mode = $passModeKeys;
|
||
$order->odds_close_time = $oddsCloseTime;
|
||
$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 = $odds;
|
||
$order->optimize_type = $optimizeType;
|
||
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();
|
||
}
|
||
|
||
// 创建组合数据
|
||
$betsInfos = $this->getZuheListFromPiaos($piaos);
|
||
$this->createZuhe($betsInfos, $order->id, $optimizeZuhe);
|
||
|
||
$orderOdds = [];
|
||
foreach ($jczqOdds as $match) {
|
||
|
||
$oldData = $odds[$match->id];
|
||
$orderOdds[] = [
|
||
'order_id' => $order->id,
|
||
'jczq_odds_id' => $match->id,
|
||
'odds_id' => $match->odds_id,
|
||
'match_id' => $match->match_id,
|
||
'created_at' => date('Y-m-d H:i:s'),
|
||
'updated_at' => date('Y-m-d H:i:s'),
|
||
];
|
||
}
|
||
OrderJczqResult::insert($orderOdds);
|
||
|
||
DB::commit();
|
||
return $order;
|
||
} catch (JingCaiException $e) {
|
||
DB::rollBack();
|
||
Log::error('jczq::order::create ValidateException: ' . $e);
|
||
throw $e;
|
||
} catch (\Exception $e) {
|
||
DB::rollBack();
|
||
Log::error('jczq::order::create Exception: ' . $e);
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
private function createZuhe($betsInfo, $orderId, $optimizeZuhe = [])
|
||
{
|
||
if ($optimizeZuhe) {
|
||
foreach ($optimizeZuhe as $item) {
|
||
$orderZuhe = new OrderZuhe();
|
||
$orderZuhe->order_id = $orderId;
|
||
$orderZuhe->jczq_odds_ids = $item['ids'];
|
||
$orderZuhe->info = $item['info'];
|
||
$orderZuhe->bets_num = $item['bets_num'];
|
||
$orderZuhe->repeat_num = Arr::get($item, 'repeat_num', 1);
|
||
$orderZuhe->save();
|
||
}
|
||
return;
|
||
}
|
||
|
||
foreach ($betsInfo as $item) {
|
||
$orderZuhe = new OrderZuhe();
|
||
$orderZuhe->order_id = $orderId;
|
||
$orderZuhe->jczq_odds_ids = $item['ids'];
|
||
$orderZuhe->info = $item['info'];
|
||
$orderZuhe->bets_num = $item['bets_num'];
|
||
$orderZuhe->repeat_num = Arr::get($item, 'repeat_num', 1);
|
||
$orderZuhe->save();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 跟单
|
||
* @param $data
|
||
* @param Customer $customer
|
||
* @return Order
|
||
* @throws \Throwable
|
||
*/
|
||
public function copyOrder(Customer $customer, Order $od, $data)
|
||
{
|
||
$betsNum = Arr::get($data, 'bets_num');
|
||
|
||
/** @var Lottery $lott */
|
||
$lott = LotteryService::getLottery($customer->shop->id, $od->lottery_type_id);
|
||
throw_if(!$lott || !$lott->isActive(), JingCaiException::create('该彩种暂不支持下单!'));
|
||
|
||
$jingcaiService = LotteryService::getJingcaiService($lott->lotteryType->type);
|
||
$odds = $jingcaiService->refreshOdds($od->odds);
|
||
$jczqOdds = JczqOdds::whereIn('id', array_keys($odds))->get();
|
||
$closeTimes = [];
|
||
foreach ($jczqOdds as $match) {
|
||
$realCloseTime = strtotime($match->real_close_time) - $lott->earlySecond();
|
||
$real_close_time = date('Y-m-d H:i:s', $realCloseTime);
|
||
$closeTimes[] = $real_close_time;
|
||
}
|
||
sort($closeTimes);
|
||
$earlyTime = $closeTimes[0];
|
||
$lateTime = $closeTimes[count($closeTimes) - 1];
|
||
$this->checkCloseTimeOver($earlyTime);
|
||
DB::beginTransaction();
|
||
try {
|
||
$passModeKeys = $od->pass_mode;
|
||
$computeInfo = $jingcaiService->computePrizeInfo($odds, $betsNum, $passModeKeys);
|
||
|
||
throw_if(!bc_gte($computeInfo['money'], $lott->min_money), JingCaiException::create('最低投注' . Helps::floatFormat($lott->min_money) . '元'));
|
||
|
||
// $betsInfos = $this->generateBetsInfo($odds,$passModeKeys, $betsNum);
|
||
|
||
// $piaos = $this->createPiaos($betsInfos);
|
||
$piaos = $this->createPiaosV2($odds, $passModeKeys, $betsNum);
|
||
$piaoZhang = array_sum(array_column($piaos, 'zhang'));
|
||
|
||
$order = new Order();
|
||
$order->type = OrderType::GENDAN;
|
||
$order->pid = $od->id;
|
||
$order->type_mode = $od->type_mode;
|
||
$order->customer_id = $customer->id;
|
||
$order->shop_id = $customer->shop_id;
|
||
$order->lottery_id = $lott->id;
|
||
$order->lottery_type_id = $lott->lottery_type_id;
|
||
$order->order_sn = Order::makeOrderSn();
|
||
$order->play_type = $od->play_type;
|
||
$order->odds_close_time = $od->odds_close_time;
|
||
$order->odds_early_close_time = $earlyTime;
|
||
$order->odds_late_close_time = $lateTime;
|
||
$order->bets_num = $betsNum;
|
||
$order->piao_num = $piaoZhang;
|
||
$order->bets_expect_num = $computeInfo['expect_bets'];
|
||
$order->zhu_num = $computeInfo['zhu_num'];
|
||
$order->money = $computeInfo['money'];
|
||
$order->prize_min = $computeInfo['prize_min'];
|
||
$order->prize_max = $computeInfo['prize_max'];
|
||
$order->pay_state = PayState::UNPAID;
|
||
$order->pass_mode = $od->pass_mode;
|
||
$order->odds = $odds;
|
||
$order->created_date = date('Ymd');
|
||
// 设置合作相关的数据
|
||
$order->setCooperateInfo($lott);
|
||
$order->save();
|
||
|
||
// 创建组合数据
|
||
$betsInfos = $this->getZuheListFromPiaos($piaos);
|
||
$this->createZuhe($betsInfos, $order->id);
|
||
|
||
$orderOddsData = [];
|
||
$jczqOdds = JczqOdds::whereIn('id', array_keys($odds))->get();
|
||
foreach ($jczqOdds as $match) {
|
||
|
||
$orderOddsData[] = [
|
||
'order_id' => $order->id,
|
||
'jczq_odds_id' => $match->id,
|
||
'odds_id' => $match->odds_id,
|
||
'match_id' => $match->match_id,
|
||
'created_at' => date('Y-m-d H:i:s'),
|
||
'updated_at' => date('Y-m-d H:i:s'),
|
||
];
|
||
}
|
||
OrderJczqResult::insert($orderOddsData);
|
||
DB::commit();
|
||
return $order;
|
||
} catch (JingCaiException $e) {
|
||
DB::rollBack();
|
||
Log::error('jczq::order::copy ValidateException: ' . $e);
|
||
throw $e;
|
||
} catch (\Exception $e) {
|
||
DB::rollBack();
|
||
Log::error('jczq::order::copy Exception: ' . $e);
|
||
throw $e;
|
||
}
|
||
}
|
||
|
||
public function showOrder(Customer $customer, Order $order)
|
||
{
|
||
$order->sellings = [];
|
||
|
||
// 截止后公开
|
||
if ($order->type_mode == 1 && ($order->type == OrderType::GENDAN || $order->type == OrderType::FADAN || $order->type == OrderType::UNION)) {
|
||
$isTypeModel1 = true;
|
||
|
||
// 合买,是自己时,全部可见
|
||
if ($order->type == OrderType::UNION) {
|
||
if ($order->customer_id == $customer->id) {
|
||
$isTypeModel1 = false;
|
||
}
|
||
}
|
||
|
||
// 跟单:如果是自己跟自己,全部可见
|
||
if ($order->type == OrderType::GENDAN) {
|
||
if ($order->customer_id == $customer->id && $order->p_order->customer_id == $customer->id) {
|
||
$isTypeModel1 = false;
|
||
}
|
||
}
|
||
|
||
// 发单:如果是自己跟自己,全部可见
|
||
if ($order->type == OrderType::FADAN) {
|
||
if ($order->customer_id == $customer->id) {
|
||
$isTypeModel1 = false;
|
||
}
|
||
}
|
||
$order->sellings = $this->getOrderOdds($order, $isTypeModel1);
|
||
} else {
|
||
// 其他公开方式
|
||
if ($order->customerCanSeeSellings($customer)) {
|
||
$order->sellings = $this->getOrderOdds($order);
|
||
}
|
||
}
|
||
|
||
if (!$order->sellings) {
|
||
$odds = $order->odds;
|
||
$jczqOddsIds = array_keys($odds);
|
||
$jczqOdds = JczqOdds::whereIn('id', $jczqOddsIds)
|
||
->where('real_close_time', '>', date('Y-m-d H:i:s'))
|
||
->first();
|
||
if (!$jczqOdds) {
|
||
$order->sellings = $this->getOrderOdds($order);
|
||
}
|
||
}
|
||
|
||
$order->chang_num = count($order->sellings);
|
||
$names = [];
|
||
foreach ($order->pass_mode as $val) {
|
||
$names[] = str_replace('.', '串', $val);
|
||
}
|
||
$order->pass_mode_names = $names;
|
||
|
||
$order->play_name = $order->lottery->name;
|
||
|
||
unset($order->lottery);
|
||
|
||
return $order;
|
||
}
|
||
|
||
public function getOrderOdds(Order $order, $isTypeModel1 = false)
|
||
{
|
||
/** @var Lottery $lottery */
|
||
$lottery = $order->lottery;
|
||
$earlyTime = $lottery->earlySecond();
|
||
|
||
$odds = $order->odds;
|
||
$jczqOddsIds = array_keys($odds);
|
||
|
||
$jczqOdds = JczqOdds::leftJoin('zq_match', 'zq_match.match_id', 'jczq_odds.match_id')
|
||
->select([
|
||
'jczq_odds.id',
|
||
'jczq_odds.issue_num',
|
||
'jczq_odds.play_num',
|
||
'jczq_odds.jc_competition_name',
|
||
'jczq_odds.jc_competition_name_full',
|
||
'jczq_odds.jc_home_team_name',
|
||
'jczq_odds.jc_home_team_name_full',
|
||
'jczq_odds.jc_away_team_name',
|
||
'jczq_odds.jc_away_team_name_full',
|
||
'jczq_odds.real_close_time',
|
||
'jczq_odds.is_reverse',
|
||
'zq_match.start_time',
|
||
])
|
||
->whereIn('jczq_odds.id', $jczqOddsIds)
|
||
->orderBy('jczq_odds.real_close_time', 'asc')
|
||
->orderBy('jczq_odds.play_num', 'asc')
|
||
->get();
|
||
|
||
$currentDate = date('Y-m-d H:i:s');
|
||
$result = [];
|
||
foreach ($jczqOdds as $item) {
|
||
$jczqResult = null;
|
||
if (in_array($order->lottery_state, Order::kaiJiangHouStates())) {
|
||
$jczqResult = JczqResult::where('jczq_odds_id', $item->id)->first();
|
||
}
|
||
$item->issue_num_week = JczqOdds::getIssueNumWeek($item->issue_num);
|
||
$item->issue_num_day = JczqOdds::getIssueNumDay($item->issue_num);
|
||
$item->vs_b = $item->jc_home_team_name;
|
||
$item->vs_m = 'vs';
|
||
$item->vs_a = $item->jc_away_team_name;
|
||
$item->play_items = $this->getOrderPlayItems($order, $item, $jczqResult);
|
||
$item->half_time_score = '';
|
||
$item->full_time_score = '';
|
||
if ($jczqResult) {
|
||
$item->half_time_score = $jczqResult->half_time_score;
|
||
$item->full_time_score = $jczqResult->full_time_score;
|
||
}
|
||
$item->lottery_close_time = date('Y-m-d H:i:s', strtotime($item->real_close_time) - $earlyTime);
|
||
|
||
$matchStartTime = $item->start_time;
|
||
if (!$matchStartTime) {
|
||
$matchStartTime = $item->lottery_close_time;
|
||
}
|
||
|
||
if ($isTypeModel1) {
|
||
if ($matchStartTime > $currentDate) {
|
||
$result[] = new \stdClass();
|
||
} else {
|
||
$result[] = $item;
|
||
}
|
||
} else {
|
||
$result[] = $item;
|
||
}
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
private function getOrderPlayItems(Order $order, $jczqOddsItem, $jczqResult)
|
||
{
|
||
$odds = $order->odds;
|
||
$buyOddsItem = Arr::get($odds, $jczqOddsItem->id);
|
||
$playTypeNames = $this->playTypeNames();
|
||
$result = [];
|
||
|
||
foreach ($playTypeNames as $playType => $name) {
|
||
$buyPlayData = Arr::get($buyOddsItem, $playType);
|
||
if (!$buyPlayData) {
|
||
continue;
|
||
}
|
||
$resultPlayTypeItem = [];
|
||
foreach ($buyPlayData as $resultField => $odds) {
|
||
|
||
$wined = false;
|
||
|
||
$buyField = str_replace('_odds', '_field', $playType);
|
||
if ($jczqResult && $jczqResult->{$buyField} == $resultField) {
|
||
$wined = true;
|
||
}
|
||
|
||
$resultPlayTypeItem[] = [
|
||
'odds_value' => $odds,
|
||
'odds_name' => $resultField,
|
||
'name' => sprintf('%s(%s)', $this->getResultFieldName($playType, $resultField), $odds),
|
||
'wined' => $wined
|
||
];
|
||
}
|
||
$winResult = '';
|
||
$resultField = str_replace('_odds', '_name', $playType);
|
||
if ($jczqResult && $jczqResult->{$resultField}) {
|
||
$winResult = $jczqResult->{$resultField};
|
||
}
|
||
//dump($resultField,$playType,$playTypeNames,$jczqResult->toArray());
|
||
|
||
$result[] = [
|
||
'win_result' => $winResult,
|
||
'play_type' => $playType,
|
||
'play_name' => $this->getPlayTypeName($playType),
|
||
'play_items' => $resultPlayTypeItem,
|
||
];
|
||
}
|
||
// dd($result);
|
||
return $result;
|
||
}
|
||
|
||
|
||
public function sellerShowOrder(Seller $seller, Order $order)
|
||
{
|
||
$order->sellings = [];
|
||
if ($order->sellerCanSeeSellings($seller)) {
|
||
$order->sellings = $this->getOrderOdds($order);
|
||
}
|
||
$order->chang_num = count($order->sellings);
|
||
$names = [];
|
||
foreach ($order->pass_mode as $val) {
|
||
$names[] = str_replace('.', '串', $val);
|
||
}
|
||
$order->pass_mode_names = $names;
|
||
|
||
$order->play_name = $order->lottery->name;
|
||
|
||
unset($order->lottery);
|
||
|
||
return $order;
|
||
}
|
||
|
||
public function chaiPiao(Order $order)
|
||
{
|
||
$optimizeZuheList = $order->zuheToOptimizeZuheList();
|
||
|
||
$piaos = $this->createPiaosV2($order->odds, $order->pass_mode, $order->bets_num, $optimizeZuheList);
|
||
|
||
|
||
$piaos = $this->chaiPiaoGenV3($piaos);
|
||
|
||
$jclqOdds = JczqOdds::whereIn('id', array_keys($order->odds))->pluck('rq_odds', 'id')->toArray();
|
||
$handicapList = [];
|
||
foreach ($jclqOdds as $id => $item) {
|
||
if ($item) {
|
||
$handicapList[$id] = $item['handicap'];
|
||
}
|
||
}
|
||
foreach ($piaos as $ind => $piao) {
|
||
$piaoOddsData = [];
|
||
$allBetsResultUnique=[];
|
||
foreach ($piao['bets'] as $piaoBet) {
|
||
foreach ($piaoBet['info'] as $id => $idInfo) {
|
||
$piaoOddsData[$id][$idInfo['play']][$idInfo['result']] = $idInfo['odd'];
|
||
}
|
||
@$allBetsResultUnique[$piaoBet['unique']] += $piaoBet['bets_num'];
|
||
}
|
||
$maxZuheList = $this->maxPrizeZuheList($piaoOddsData, $piao['pass_mode'], $handicapList);
|
||
|
||
$maxPrize = 0;
|
||
foreach ($maxZuheList as $zuhe) {
|
||
$repeatNum = $allBetsResultUnique[$zuhe['unique']];
|
||
$maxPrize += $repeatNum * $this->getBetsInfoPrize($zuhe);
|
||
}
|
||
$piaos[$ind]['prize_max'] = $maxPrize;
|
||
}
|
||
$header = [
|
||
[
|
||
'prop' => 'index',
|
||
'title' => '序号',
|
||
],
|
||
[
|
||
'prop' => 'type',
|
||
'title' => '过关',
|
||
],
|
||
[
|
||
'prop' => 'play_name',
|
||
'title' => $order->play_type_name,
|
||
],
|
||
[
|
||
'prop' => 'nums',
|
||
'title' => '倍数/票数',
|
||
],
|
||
];
|
||
$piaoList = [];
|
||
|
||
foreach ($piaos as $k => $piao) {
|
||
|
||
$buyOdds = [
|
||
];
|
||
foreach ($piao['bets'] as $betInfo) {
|
||
$piaoInfo = $betInfo['info'];
|
||
|
||
foreach ($piaoInfo as $id => $info) {
|
||
$buyField = $this->getResultFieldName($info['play'], $info['result']);
|
||
if (!isset($buyOdds[$id])) {
|
||
$buyOdds[$id] = [$buyField];
|
||
continue;
|
||
}
|
||
if (!in_array($buyField,$buyOdds[$id])) {
|
||
$buyOdds[$id][] = $buyField;
|
||
}
|
||
}
|
||
}
|
||
$jczqOdds = JczqOdds::whereIn('id',array_keys($buyOdds))
|
||
->orderBy('play_num', 'desc')
|
||
->get()
|
||
->keyBy('id');
|
||
|
||
$plays = [];
|
||
foreach ($buyOdds as $id => $fields) {
|
||
/** @var JczqOdds $oddItem */
|
||
$oddItem = Arr::get($jczqOdds, $id);
|
||
$weekPlay = $oddItem->weekPlayFormat();
|
||
$plays[] = $weekPlay . ' (' . implode(' ', $fields) .')';
|
||
}
|
||
if ($piao['zhang'] > 1) {
|
||
$piaoMoney = $piao['zhu_money'] * 50;
|
||
$beishu = 50;
|
||
} else {
|
||
$piaoMoney = $piao['zhu_money'] * $piao['bets_num'];
|
||
$beishu = $piao['bets_num'];
|
||
}
|
||
$piaoList[] = [
|
||
'header' => $header,
|
||
'data' => [
|
||
'index' => $k +1 ,
|
||
'type' => $order->getPassModelNameByKeys($piao['pass_mode']),
|
||
'play_name' => $plays,
|
||
'nums' => sprintf('%d倍/%d张', $beishu, $piao['zhang'])
|
||
],
|
||
'summary' => '',
|
||
'zhang' => $piao['zhang'],
|
||
'zhu_money' => $piao['zhu_money'],
|
||
'piao_money' => $piaoMoney,
|
||
// 'prize_max' => Helps::floatFormat($piao['prize']/$piao['zhang']),
|
||
'prize_max' => Helps::floatFormat($piao['prize_max']),
|
||
];
|
||
}
|
||
return $piaoList;
|
||
}
|
||
}
|