2432 lines
84 KiB
PHP
2432 lines
84 KiB
PHP
<?php
|
|
|
|
require_once('mt/Shop.php');
|
|
require_once('mt/ShopGoods.php');
|
|
require_once('mt/Hero.php');
|
|
require_once('mt/Item.php');
|
|
require_once('mt/Parameter.php');
|
|
require_once('mt/Drop.php');
|
|
require_once('mt/PayMethod.php');
|
|
require_once('mt/Dailyselection.php');
|
|
require_once('mt/ShopChest.php');
|
|
|
|
require_once('models/User.php');
|
|
require_once('models/Hero.php');
|
|
require_once('models/Bag.php');
|
|
require_once('models/HeroSkin.php');
|
|
require_once('models/Gun.php');
|
|
require_once('models/GunSkin.php');
|
|
require_once('models/ShopBuyRecord.php');
|
|
require_once('models/Chip.php');
|
|
require_once('models/BcOrder.php');
|
|
require_once('models/Transaction.php');
|
|
|
|
require_once('services/AwardService.php');
|
|
require_once('services/PropertyChgService.php');
|
|
require_once('services/BlockChainService.php');
|
|
|
|
require_once('phpcommon/bignumber.php');
|
|
|
|
require_once('services/LogService.php');
|
|
require_once('services/callback/ShopAddItemService.php');
|
|
|
|
// use phpcommon;
|
|
use phpcommon\HttpClient;
|
|
use phpcommon\SqlHelper;
|
|
use models\User;
|
|
use models\Bag;
|
|
use models\Hero;
|
|
use models\HeroSkin;
|
|
use models\Gun;
|
|
use models\GunSkin;
|
|
use models\ShopBuyRecord;
|
|
use models\Chip;
|
|
use mt\Shop;
|
|
use mt\PayMethod;
|
|
use mt\Dailyselection;
|
|
use mt\ShopChest;
|
|
use models\Transaction;
|
|
use models\BcOrder;
|
|
use services\LogService;
|
|
use services\ShopAddItemService;
|
|
|
|
if (!function_exists('array_column')) {
|
|
function array_column($arr2, $column_key)
|
|
{
|
|
$data = [];
|
|
foreach ($arr2 as $arr) {
|
|
$data[] = $arr[$column_key];
|
|
}
|
|
return $data;
|
|
}
|
|
}
|
|
|
|
class ShopController extends BaseAuthedController
|
|
{
|
|
|
|
const TOKEN_TYPE_GOLD = '0';
|
|
const TOKEN_TYPE_CEG = '1';
|
|
const TOKEN_TYPE_CEC = '2';
|
|
const TOKEN_TYPE_BCEG = '3';
|
|
const TOKEN_TYPE_DIAMOND = '4';
|
|
|
|
|
|
const TOKEN_TYPE_USDT = '11';
|
|
const TOKEN_TYPE_USDC = '12';
|
|
const TOKEN_TYPE_BUSD = '13';
|
|
|
|
const TOKEN_TYPE_MATIC = '101';
|
|
const TOKEN_TYPE_BNB = '102';
|
|
|
|
//99 = 美元
|
|
const TOKEN_TYPE_USD = '99';
|
|
|
|
//21 = 印尼
|
|
const TOKEN_TYPE_IDR = '21';
|
|
//22 = 菲律宾
|
|
const TOKEN_TYPE_PHP = '22';
|
|
//23 = 越南
|
|
const TOKEN_TYPE_VND = '23';
|
|
//24 = 泰国
|
|
const TOKEN_TYPE_THB = '24';
|
|
//25 = 马来西亚
|
|
const TOKEN_TYPE_MYR = '25';
|
|
//26 = 日本
|
|
const TOKEN_TYPE_JPY = '26';
|
|
//27 = 韩国
|
|
const TOKEN_TYPE_KRW = '27';
|
|
|
|
|
|
// 限购类型
|
|
const DAILY_BUY_LIMIT = 1;
|
|
const WEEKLY_BUY_LIMIT = 2;
|
|
const TOTAL_BUY_LIMIT = 3;
|
|
|
|
public function _handlePre()
|
|
{
|
|
// if (SERVER_ENV == _ONLINE) {
|
|
// if (getReqVal('client_uuid', '') != '499af8a0-a1bc-0b0e-dc79-a42cb3f103dc') {
|
|
// if ((getReqVal('c', '') != 'Battle')) {
|
|
// phpcommon\sendError(1001, 'session expiration');
|
|
// die();
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
$a = getReqVal('a', '');
|
|
if (
|
|
$a != 'buyGoodsDirect' &&
|
|
$a != 'inappPurchaseDiamonds'
|
|
) {
|
|
parent::_handlePre();
|
|
}
|
|
}
|
|
|
|
public function getGoodsList()
|
|
{
|
|
$shop_id = getReqVal('shop_id', 0);
|
|
if ($shop_id == 0) {
|
|
$goodsList = mt\ShopGoods::all();
|
|
} else {
|
|
$goodsList = mt\ShopGoods::getGoodsList($shop_id);
|
|
}
|
|
|
|
$goodsList = $goodsList ? $goodsList : array();
|
|
$buyRecordHash = ShopBuyRecord::allToHash();
|
|
|
|
foreach ($goodsList as &$goods) {
|
|
$goods['bought_times'] = 0;
|
|
switch ($goods['limit_type']) {
|
|
case mt\Item::DAILY_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $goods['id']);
|
|
$goods['bought_times'] = $buyRecord ? $buyRecord['this_day_buy_times'] : 0;
|
|
}
|
|
break;
|
|
case mt\Item::WEEKLY_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $goods['id']);
|
|
$goods['bought_times'] = $buyRecord ? $buyRecord['this_week_buy_times'] : 0;
|
|
}
|
|
break;
|
|
case mt\Item::TOTAL_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $goods['id']);
|
|
$goods['bought_times'] = $buyRecord ? $buyRecord['total_buy_times'] : 0;
|
|
}
|
|
break;
|
|
default: {
|
|
}
|
|
break;
|
|
}
|
|
if (empty($goods['goods_num'])) {
|
|
$goods['goods_num'] = 1;
|
|
}
|
|
if (!empty($goods['free_type'])) {
|
|
$count = $this->countFreeBuyTimes($goods['free_type'], $goods['id'], $goods['goods_id']);
|
|
$goods['free_num'] = $goods['free_num'] - $count;
|
|
// error_log('free_num:' . $goods['free_num']);
|
|
}
|
|
|
|
$address = $this->_getAddress();
|
|
if ($address) {
|
|
$goods['pending'] = $this->checkPendingBuyGoodsNormal($address, $goods['goods_id'], $goods['shop_id'], $goods['id']);
|
|
}
|
|
}
|
|
|
|
$this->_rspData(
|
|
array(
|
|
'goods_list' => $goodsList,
|
|
)
|
|
);
|
|
}
|
|
|
|
public function getShopNames()
|
|
{
|
|
$shopList = mt\Shop::all();
|
|
|
|
$this->_rspData(
|
|
array(
|
|
'shop_name_list' => $shopList ? $shopList : array(),
|
|
)
|
|
);
|
|
}
|
|
|
|
public function startGoodsDirect()
|
|
{
|
|
$id = getReqVal('id', 0);
|
|
$token_type = getReqVal('token_type', '');
|
|
$goods_num = getReqVal('goods_num', 1);
|
|
|
|
if ($goods_num <= 0) {
|
|
$this->_rspErr(1, 'goods_num is invalid');
|
|
}
|
|
|
|
$goods = mt\ShopGoods::get($id);
|
|
if ($goods['shop_id'] == 9 && $goods_num > 1) {
|
|
$this->_rspErr(1, 'goods_num is invalid');
|
|
}
|
|
|
|
$conn = myself()->_getMysql('');
|
|
|
|
$address = myself()->_getAddress();
|
|
if (!$address) {
|
|
$this->_rspErr(1, 'address is empty');
|
|
}
|
|
|
|
$chk = SqlHelper::insert(
|
|
$conn,
|
|
't_shop_buy_order',
|
|
array(
|
|
'address' => $address,
|
|
'createtime' => myself()->_getNowTime(),
|
|
'id' => $id,
|
|
'item_id' => $goods['goods_id'],
|
|
'goods_num' => $goods_num,
|
|
'status' => 0, // 0-客户端申请了订单 1-订单完成 2-订单失败
|
|
)
|
|
);
|
|
if ($chk) {
|
|
$lastId = $this->lastInsertId($conn);
|
|
$this->_rspData(
|
|
array(
|
|
'order_id' => $lastId,
|
|
)
|
|
);
|
|
} else {
|
|
$this->_rspErr(1, "insert error, id: {$id}, token_type: {$token_type}, goods_num: {$goods_num}");
|
|
}
|
|
}
|
|
|
|
public function statusGoodsDirect()
|
|
{
|
|
$order_id = getReqVal('order_id', '');
|
|
|
|
$conn = myself()->_getMysql('');
|
|
|
|
$row = SqlHelper::selectOne(
|
|
$conn,
|
|
't_shop_buy_order',
|
|
array('status', 'id'),
|
|
array(
|
|
'idx' => $order_id,
|
|
)
|
|
);
|
|
if ($row) {
|
|
$this->_rspData(
|
|
array(
|
|
'status' => $row['status'],
|
|
'item_id' => $row['item_id'],
|
|
'item_num' => $row['goods_num'],
|
|
)
|
|
);
|
|
} else {
|
|
$this->_rspErr(1, "order_id not found, order_id: {$order_id}");
|
|
}
|
|
}
|
|
|
|
// callback from (hongliang) server
|
|
public function buyGoodsDirect()
|
|
{
|
|
// let repdata = {
|
|
// account_id: string
|
|
// order_id: string
|
|
// status: string
|
|
// id: string
|
|
// txhash: string
|
|
// }
|
|
// 我返回给你这些数据和一个sign字段,
|
|
// sign使用上面 repdata 按key 顺序排后, 组成key1=val1&key2=val2后, 使用hmac_sha256 hash, key是 iG4Rpsa)6U31$H#^T85$^^3
|
|
// PENDING = 0, // 初始状态
|
|
// TRANSFERING = 1, //只有国库模式才会有该状态
|
|
// TRANSFERED = 2, //只有国库模式才会有该状态
|
|
// SUCCESS = 9, // 成功的最终状态
|
|
// TRANSFER_FAIL = 98, // 转账错误
|
|
// FAIL = 99, // 也是错误
|
|
//
|
|
|
|
$account_id = getReqVal('account_id', '');
|
|
$order_id = getReqVal('order_id', '');
|
|
$status = getReqVal('status', '');
|
|
$id = getReqVal('id', '');
|
|
$txhash = getReqVal('txhash', '');
|
|
|
|
$sign = getReqVal('sign', '');
|
|
|
|
$data = array(
|
|
'account_id' => $account_id,
|
|
'id' => $id,
|
|
'order_id' => $order_id,
|
|
'status' => $status,
|
|
'txhash' => $txhash,
|
|
);
|
|
|
|
$hash_data = http_build_query($data);
|
|
|
|
$signature = hash_hmac('sha256', $hash_data, 'iG4Rpsa)6U31$H#^T85$^^3');
|
|
|
|
if ($signature != $sign) {
|
|
$this->_rspErr(1, "signature error, signature: {$signature}, sign: {$sign}");
|
|
return;
|
|
}
|
|
|
|
error_log("buyGoodsDirect-------" . $order_id . "---" . $status);
|
|
|
|
$conn = myself()->_getMysql('');
|
|
|
|
$order = SqlHelper::selectOne($conn, 't_shop_buy_order', array('address', 'item_id', 'goods_num', 'status'), array('idx' => $order_id));
|
|
|
|
$id = $order['item_id'];
|
|
$goods_num = $order['goods_num'];
|
|
$o_status = $order['status'];
|
|
|
|
if ($o_status != 0) {
|
|
$this->_rspErr(1, "order status error, status: {$o_status}");
|
|
return;
|
|
}
|
|
|
|
$buyStatus = 0; // 1: 成功, 2: 失败
|
|
switch ($status) {
|
|
case "9":
|
|
$buyStatus = 1;
|
|
break;
|
|
case "99":
|
|
case "98":
|
|
$buyStatus = 2;
|
|
break;
|
|
}
|
|
|
|
SqlHelper::update($conn, 't_shop_buy_order', array('idx' => $order_id), array('status' => $buyStatus));
|
|
|
|
$row = mt\ShopGoods::get($id);
|
|
if ($row) {
|
|
$desired_token_type = $row['token_type'];
|
|
$check_token_type = splitStr1($desired_token_type);
|
|
// $token_pos = array_search($token_type, $check_token_type, true);
|
|
// if (!in_array($token_type, $check_token_type)) {
|
|
// $this->_rspErr(1, "token_type parameter error, desired_token_type: {$desired_token_type}");
|
|
// return;
|
|
// }
|
|
|
|
if ($goods_num > $row['max_amount']) {
|
|
$this->_rspErr(1, "goods_num parameter error, max_amount: {$row['max_amount']}");
|
|
return;
|
|
}
|
|
|
|
// 这里命名混乱了, 购买个数,一捆个数命名冲突
|
|
$goods_count = $row['goods_num'];
|
|
|
|
$itemMeta = mt\Item::get($row['goods_id']);
|
|
$propertyChgService = new services\PropertyChgService();
|
|
for ($i = 0; $i < $goods_num; $i++) {
|
|
// 既然这种货币是在链上的,那么这里不应该增加任何物品,
|
|
// $this->internalAddItem($propertyChgService, $itemMeta, $goods_count, 0);
|
|
}
|
|
$awardService = new services\AwardService();
|
|
// $awardService->addItem($row['goods_id'], $goods_num);
|
|
ShopBuyRecord::add($id, $goods_num);
|
|
}
|
|
|
|
$this->_rspOk();
|
|
}
|
|
|
|
public function startInappPurchase()
|
|
{
|
|
$self = myself();
|
|
if (!$self) {
|
|
$this->_rspErr(1, "start purchase failed");
|
|
return;
|
|
}
|
|
|
|
$id = getReqVal('id', 0);
|
|
$goods = mt\ShopGoods::get($id);
|
|
if (!$goods) {
|
|
$this->_rspErr(2, "start purchase failed");
|
|
return;
|
|
}
|
|
if ($goods['shop_id'] != 9) {
|
|
$this->_rspErr(3, "start purchase failed");
|
|
return;
|
|
}
|
|
|
|
$goods_num = getReqVal('goods_num', 1);
|
|
|
|
$account_id = $self->_getAccountId();
|
|
$address = $self->_getAddress();
|
|
|
|
$item_id = $goods['goods_id'];
|
|
$item_num = $goods['goods_num'] * $goods_num;
|
|
|
|
$conn = $self->_getMysql('');
|
|
|
|
$chk = SqlHelper::insert($conn, 't_web2_order', array(
|
|
'status' => 0,
|
|
'createtime' => $self->_getNowTime(),
|
|
'account_id' => $account_id,
|
|
'address' => $address,
|
|
'item_id' => $item_id,
|
|
'item_num' => $item_num,
|
|
'id' => $id,
|
|
'goods_num' => $goods_num,
|
|
'price' => $goods['price'],
|
|
));
|
|
|
|
if (!$chk) {
|
|
$this->_rspErr(4, "start purchase failed");
|
|
return;
|
|
}
|
|
$lastId = $this->lastInsertId($conn);
|
|
// gen order id
|
|
$order_id_base = date('YmdHis') . "10000000";
|
|
$divIdx = ($lastId) % 9999999;
|
|
|
|
$order_id = phpcommon\bnAdd_s($order_id_base, $divIdx);
|
|
$test = SqlHelper::update($conn, 't_web2_order', array('idx' => $lastId), array('order_id' => $order_id));
|
|
if (!$test) {
|
|
$this->_rspErr(5, "start purchase failed");
|
|
return;
|
|
}
|
|
$this->_rspData(array(
|
|
'order_id' => $order_id,
|
|
));
|
|
}
|
|
|
|
public function statusInappPurchase()
|
|
{
|
|
$order_id = getReqVal('order_id', '');
|
|
$conn = myself()->_getMysql('');
|
|
$order = SqlHelper::selectOne($conn, 't_web2_order', array('item_id', 'item_num', 'status'), array('order_id' => $order_id));
|
|
if (!$order) {
|
|
$this->_rspErr(1, "order not found");
|
|
return;
|
|
}
|
|
$this->_rspData($order);
|
|
}
|
|
|
|
public function inappPurchaseDiamonds()
|
|
{
|
|
error_log('----- inappPurchaseDiamonds -----');
|
|
error_log('request:' . json_encode($_REQUEST));
|
|
error_log('post:' . json_encode($_POST));
|
|
$body = json_decode(file_get_contents('php://input'), true);
|
|
error_log('body:' . json_encode($body));
|
|
$channel = $body['channel'];
|
|
$records = $body['records'];
|
|
$sign = $body['sign'];
|
|
|
|
error_log('records:' . json_encode($records));
|
|
|
|
// {
|
|
// channel: 'google',
|
|
// sign: '123456677' // 签名字段
|
|
// records: [{
|
|
// productId: '2999', // 从google play console获取的product id
|
|
// gameOrderId: '1231321312', // 开始支付时, 从游戏相关服务那获得的订单id
|
|
// orderId: 'GPA.3355-1172-9416-16839', // 从google develope API 获取的订单id
|
|
// status: 9, // 订单状态, 上报的订单状态一般只有2种情况, 9: 支付成功, 96: 用户退款
|
|
// }]
|
|
// }
|
|
// let reportData: any = {
|
|
// channel: 'google',
|
|
// records,
|
|
// }
|
|
// const hashSort = 'iG4Rpsa)6U31$H#^T85$^^3'
|
|
// const signStr = 'channel=google&' + records.map(record =>Object.keys(record).sort().map(key => `${key}=${record[key]}`).join('&')).join('&')
|
|
|
|
// const sign = hmacsha256(signStr, hashSort)
|
|
|
|
// 定义一个空数组,用来存放每个记录的键值对字符串
|
|
$record_strings = array();
|
|
|
|
// 遍历 records 数组,对每个记录进行排序和拼接
|
|
foreach ($records as $record) {
|
|
// 对记录的键进行升序排序
|
|
ksort($record);
|
|
// 把记录的键值对用等号连接,然后用 & 连接成一个字符串
|
|
$record_string = http_build_query($record);
|
|
// 把字符串加入到 record_strings 数组中
|
|
$record_strings[] = $record_string;
|
|
}
|
|
|
|
// 把 record_strings 数组用 & 连接成一个字符串
|
|
$records_string = implode("&", $record_strings);
|
|
|
|
$hash_data = 'channel=' . $channel . '&' . $records_string;
|
|
|
|
$signature = hash_hmac('sha256', $hash_data, 'iG4Rpsa)6U31$H#^T85$^^3');
|
|
|
|
if ($signature != $sign) {
|
|
$this->_rspErr(1, "signature error, signature: {$signature}, sign: {$sign}");
|
|
return;
|
|
}
|
|
|
|
$conn = myself()->_getMysql('');
|
|
// 有三种情况:
|
|
// 1. 从商城购买钻石,有订单号
|
|
// 2. 站外充值钻石,没有订单号
|
|
// 3. appstore 退款,没有订单号
|
|
|
|
for ($i = 0; $i < count($records); $i++) {
|
|
$record = $records[$i];
|
|
|
|
$product_id = $record['productId'];
|
|
$order_id = $record['gameOrderId'];
|
|
$out_order_id = $record['orderId'];
|
|
$status = $record['status'];
|
|
|
|
switch ($status) {
|
|
case 9: {
|
|
$status = 1;
|
|
if (empty($order_id)) {
|
|
if (empty($product_id)) {
|
|
$this->_rspErr(2, "product_id is empty");
|
|
return;
|
|
}
|
|
// $goods = mt\ShopGoods::getByProductId($product_id);
|
|
|
|
return;
|
|
}
|
|
|
|
$order = SqlHelper::selectOne($conn, 't_web2_order', array('address', 'id', 'item_id', 'goods_num', 'status'), array('order_id' => $order_id, 'status' => 0));
|
|
error_log('process order '. json_encode($order));
|
|
if (!$order) {
|
|
$this->_rspErr(3, "order not found, order_id: {$order_id}");
|
|
return;
|
|
}
|
|
|
|
SqlHelper::update($conn, 't_web2_order', array('order_id' => $order_id), array('status' => $status, 'channel' => $channel, 'out_order_id' => $out_order_id));
|
|
|
|
$id = $order['id'];
|
|
$goods = mt\ShopGoods::get($id);
|
|
// 这里命名混乱了, 购买个数,一捆个数命名冲突
|
|
$goods_num = $order['goods_num'];
|
|
$bundle_size = $goods['goods_num'];
|
|
$item_num = $goods_num * $bundle_size;
|
|
$item_id = $goods['goods_id'];
|
|
$address = $order['address'];
|
|
$account_id = $this->getAccountId($address);
|
|
|
|
if ($item_id == V_ITEM_DIAMOND) {
|
|
$event = [
|
|
'name' => LogService::RECHARGE_DIAMOND,
|
|
'val' => $item_num
|
|
];
|
|
LogService::productDiamond(['account_id' => $account_id], $event);
|
|
}
|
|
|
|
$this->_addGoods($address, array(
|
|
'goods_id' => $item_id,
|
|
'goods_num' => $item_num,
|
|
'id' => $id,
|
|
));
|
|
}
|
|
break;
|
|
case 96:
|
|
// 退款
|
|
$status = 2;
|
|
break;
|
|
default:
|
|
$status = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
$this->_rspOk();
|
|
}
|
|
|
|
private function getAccountId($address)
|
|
{
|
|
$row = SqlHelper::ormSelectOne(
|
|
myself()->_getMysql($address),
|
|
't_user',
|
|
array(
|
|
'address' => $address
|
|
)
|
|
);
|
|
return $row['account_id'];
|
|
}
|
|
|
|
private function _addGoods($address, $goods)
|
|
{
|
|
$itemService = new ShopAddItemService();
|
|
$item_id = $goods['goods_id'];
|
|
$goods_num = $goods['goods_num'];
|
|
|
|
$id = null;
|
|
if ($goods['id']) {
|
|
$id = $goods['id'];
|
|
}
|
|
|
|
error_log(json_encode($goods));
|
|
error_log('_addGoods ' . $address . ' item_id ' . $item_id . ' goods_num ' . $goods_num . ' id ' . $id);
|
|
$itemService->addItem($address, $item_id, $goods_num);
|
|
if ($id) {
|
|
ShopBuyRecord::addWithAddress($address, $id, $goods_num);
|
|
}
|
|
}
|
|
|
|
public function getPayMethods()
|
|
{
|
|
$token_type = getReqVal('token_type', 99);
|
|
$payMethods = mt\PayMethod::getPayMethods($token_type);
|
|
$this->_rspData(
|
|
array(
|
|
'pay_methods' => $payMethods,
|
|
)
|
|
);
|
|
}
|
|
|
|
public function refreshDailySelection()
|
|
{
|
|
$address = $this->_getAccountId();
|
|
|
|
$maxCount = mt\Parameter::getByName('daily_selection_refresh_time')['param_value'];
|
|
$count = $this->countTodayRefreshTimes($address);
|
|
if ($count >= $maxCount) {
|
|
$this->_rspErr(2, 'The maximum number of refreshes has been reached');
|
|
return;
|
|
}
|
|
|
|
$count = $this->countTodayRefreshTimes($address);
|
|
$costs = mt\Parameter::getByName('daily_selection_refresh_cost');
|
|
$arrCosts = explode('|', $costs['param_value']);
|
|
$cost = $arrCosts[$count];
|
|
$costItemId = $this->getCostItemIdByTokenType(ShopController::TOKEN_TYPE_GOLD);
|
|
$costItems = $this->makeCostItems($costItemId, $cost);
|
|
$lackItem = null;
|
|
if (!$this->_hasEnoughItems($costItems, $lackItem)) {
|
|
$this->_rspErr(2, $this->_getLackItemErrMsg($lackItem));
|
|
return;
|
|
}
|
|
|
|
$chk = $this->refreshDailySelectionWithMode($address, 1);
|
|
if ($chk) {
|
|
$this->_decItems($costItems);
|
|
|
|
error_log("refreshDailySelection-------" . $address . "---" . $cost);
|
|
$this->_rspData(
|
|
array(
|
|
'cost' => $cost,
|
|
)
|
|
);
|
|
} else {
|
|
$this->_rspErr(3, 'refresh failed');
|
|
}
|
|
}
|
|
|
|
public function getDailySelectionList()
|
|
{
|
|
$address = $this->_getAccountId();
|
|
|
|
// 不清除过期的每日精选可以避免跨日操作错误
|
|
// $chk = $this->clearBeforeTodayDailySelections();
|
|
|
|
$chk = $this->getTodayLastDailySelection($address);
|
|
if (!$chk) {
|
|
$chk = $this->refreshDailySelectionWithMode($address, 0);
|
|
$chk = $this->getTodayLastDailySelection($address);
|
|
}
|
|
|
|
$selection = $chk[0];
|
|
$goodsList = array();
|
|
for ($i = 1; $i <= 6; $i++) {
|
|
$goodsList[$i] = mt\Dailyselection::get($selection['grid_' . $i]);
|
|
$goodsList[$i]['count'] = $selection['count_' . $i];
|
|
$goodsList[$i]['pending'] = $this->checkPendingBuyGoodsDS($address, $goodsList[$i]['goods_id'], $selection['idx'], $i);
|
|
}
|
|
|
|
$count = $this->countTodayRefreshTimes($address);
|
|
$costs = mt\Parameter::getByName('daily_selection_refresh_cost');
|
|
$arrCosts = explode('|', $costs['param_value']);
|
|
|
|
$max_count = count($arrCosts);
|
|
$cost = $count < $max_count ? $arrCosts[$count] : -1;
|
|
|
|
// error_log('getDailySelectionList address: ' . $address . ' idx:' . $selection['idx'] . ' refresh_info:' . "{$count}/{$max_count}" . ' cost:' . $cost);
|
|
|
|
$this->_rspData(
|
|
array(
|
|
'idx' => $selection['idx'],
|
|
'refresh_info' => "{$count}/{$max_count}",
|
|
'cost' => $cost,
|
|
'goods_list' => $goodsList,
|
|
)
|
|
);
|
|
}
|
|
|
|
public function buyGoodsNormal()
|
|
{
|
|
$address = $this->_getAddress();
|
|
// if (empty($address)) {
|
|
// $this->_rspErr(4, 'address is empty');
|
|
// return;
|
|
// }
|
|
$id = getReqVal('id', 0);
|
|
$token_type = getReqVal('token_type', '');
|
|
$goods_num = getReqVal('goods_num', 0);
|
|
|
|
if ($goods_num < 1) {
|
|
$this->_rspErr(1, "goods_num parameter error, goods_num: {$goods_num}");
|
|
return;
|
|
}
|
|
|
|
$row = mt\ShopGoods::get($id);
|
|
|
|
if (!$row) {
|
|
$this->_rspErr(1, 'goods not found');
|
|
return;
|
|
}
|
|
|
|
$goods_id = $row['goods_id'];
|
|
if (!empty($address)) {
|
|
$pending = $this->checkPendingBuyGoodsNormal($address, $goods_id, $row['shop_id'], $id);
|
|
if ($pending) {
|
|
$this->_rspErr(1, 'pending');
|
|
return;
|
|
}
|
|
}
|
|
|
|
$desired_token_type = $row['token_type'];
|
|
$check_token_type = splitStr1($desired_token_type);
|
|
$token_pos = array_search($token_type, $check_token_type, true);
|
|
$isFreeBuy = false;
|
|
if (!empty($row['free_type'])) {
|
|
$count = $this->countFreeBuyTimes($row['free_type'], $row['id'], $row['goods_id']);
|
|
if ($count < $row['free_num']) {
|
|
$isFreeBuy = true;
|
|
}
|
|
}
|
|
if (!$isFreeBuy) {
|
|
if (!in_array($token_type, $check_token_type)) {
|
|
$this->_rspErr(1, "token_type parameter error, desired_token_type: {$desired_token_type}");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ($goods_num > $row['max_amount']) {
|
|
$this->_rspErr(1, "goods_num parameter error, max_amount: {$row['max_amount']}");
|
|
return;
|
|
}
|
|
|
|
// 这里命名混乱了, 购买个数,一捆个数命名冲突
|
|
$goods_count = $row['goods_num'];
|
|
|
|
$buyRecordHash = ShopBuyRecord::allToHash();
|
|
$boughtTimes = 1;
|
|
switch ($row['limit_type']) {
|
|
case ShopController::DAILY_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $id);
|
|
$boughtTimes = $buyRecord ? $buyRecord['this_day_buy_times'] + 1 : 1;
|
|
if ($buyRecord && getXVal($buyRecord, 'this_day_buy_times', 0) >= $row['limit_num']) {
|
|
$this->_rspErr(2, 'Daily purchase limit');
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case ShopController::WEEKLY_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $id);
|
|
$boughtTimes = $buyRecord ? $buyRecord['this_week_buy_times'] + 1 : 1;
|
|
if ($buyRecord && getXVal($buyRecord, 'this_week_buy_times', 0) >= $row['limit_num']) {
|
|
$this->_rspErr(2, 'Weekly purchase limit reached');
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case ShopController::TOTAL_BUY_LIMIT: {
|
|
// error_log("total buy limit " . $address . " " . $id . " " . $row['limit_num']);
|
|
$buyRecord = getXVal($buyRecordHash, $id);
|
|
$boughtTimes = $buyRecord ? $buyRecord['total_buy_times'] + 1 : 1;
|
|
if ($buyRecord && getXVal($buyRecord, 'total_buy_times', 0) >= $row['limit_num']) {
|
|
$this->_rspErr(2, 'Purchase limit reached');
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
default: {
|
|
}
|
|
break;
|
|
}
|
|
|
|
$price_array = splitStr1($row['price']);
|
|
$discount_array = splitStr1($row['discount']);
|
|
|
|
$need_price = $price_array[$token_pos];
|
|
$discount = $discount_array[$token_pos];
|
|
|
|
$discount_begin = strtotime($row['discount_begin']);
|
|
$discount_end = strtotime($row['discount_end']);
|
|
$nowTime = $this->_getNowTime();
|
|
|
|
if ($nowTime >= $discount_begin && $nowTime < $discount_end) {
|
|
|
|
$need_price = ceil($need_price * ($discount / 100.0));
|
|
}
|
|
|
|
$costItemId = $this->getCostItemIdByTokenType($token_type);
|
|
|
|
switch ($token_type) {
|
|
case ShopController::TOKEN_TYPE_GOLD:
|
|
$costItems = $this->makeCostItems($costItemId, $goods_num * $need_price);
|
|
$lackItem = null;
|
|
if (!$this->_hasEnoughItems($costItems, $lackItem)) {
|
|
$this->_rspErr(2, $this->_getLackItemErrMsg($lackItem));
|
|
return;
|
|
}
|
|
|
|
$itemMeta = mt\Item::get($row['goods_id']);
|
|
$propertyChgService = new services\PropertyChgService();
|
|
for ($i = 0; $i < $goods_num; $i++) {
|
|
$this->internalAddItem($propertyChgService, $itemMeta, $goods_count, 0);
|
|
}
|
|
$awardService = new services\AwardService();
|
|
$awardService->addItem($row['goods_id'], $goods_num);
|
|
ShopBuyRecord::add($id, $goods_num);
|
|
$this->_decItems($costItems);
|
|
$goodsDto = array(
|
|
'goods_id' => $id,
|
|
'item_id' => $row['goods_id'],
|
|
'price_info' => array(
|
|
'item_id' => $row['goods_id'],
|
|
'cost_list' => array(),
|
|
'discount_begin_time' => phpcommon\datetimeToTimestamp($row['discount_begin']),
|
|
'discount_end_time' => phpcommon\datetimeToTimestamp($row['discount_end'])
|
|
),
|
|
'flag_icon' => $row['tag'],
|
|
'limit_type' => $row['limit_type'],
|
|
'bought_times' => $boughtTimes,
|
|
'total_buy_times' => $row['limit_num'],
|
|
); {
|
|
$priceInfo = mt\Item::getPriceInfo($itemMeta);
|
|
if (!empty($priceInfo)) {
|
|
$goodsDto['price_info'] = $priceInfo['price_info'];
|
|
}
|
|
}
|
|
$propertyChgService->addUserChg();
|
|
$this->_rspData(
|
|
array(
|
|
'award' => $awardService->toDto(),
|
|
'property_chg' => $propertyChgService->toDto(),
|
|
'goods_chg' => $goodsDto
|
|
)
|
|
);
|
|
break;
|
|
case ShopController::TOKEN_TYPE_DIAMOND:
|
|
if ($isFreeBuy) {
|
|
$need_price = 0;
|
|
}
|
|
$costItems = $this->makeCostItems($costItemId, $goods_num * $need_price);
|
|
$lackItem = null;
|
|
if (!$this->_hasEnoughItems($costItems, $lackItem)) {
|
|
$this->_rspErr(2, $this->_getLackItemErrMsg($lackItem));
|
|
return;
|
|
}
|
|
|
|
$itemMeta = mt\Item::get($row['goods_id']);
|
|
$propertyChgService = new services\PropertyChgService();
|
|
for ($i = 0; $i < $goods_num; $i++) {
|
|
$this->internalAddItem($propertyChgService, $itemMeta, $goods_count, 0);
|
|
}
|
|
$awardService = new services\AwardService();
|
|
$awardService->addItem($row['goods_id'], $goods_num);
|
|
ShopBuyRecord::add($id, $goods_num);
|
|
if ($isFreeBuy) {
|
|
$this->addFreeBuyRecord($row);
|
|
}
|
|
$this->_decItems($costItems);
|
|
$event = [
|
|
'name' => LogService::SHOP_BUY_ITEM,
|
|
'val' => $costItems[0]['item_num']
|
|
];
|
|
LogService::consumeDiamond($event);
|
|
|
|
$goodsDto = array(
|
|
'goods_id' => $id,
|
|
'item_id' => $row['goods_id'],
|
|
'price_info' => array(
|
|
'item_id' => $row['goods_id'],
|
|
'cost_list' => array(),
|
|
'discount_begin_time' => phpcommon\datetimeToTimestamp($row['discount_begin']),
|
|
'discount_end_time' => phpcommon\datetimeToTimestamp($row['discount_end'])
|
|
),
|
|
'flag_icon' => $row['tag'],
|
|
'limit_type' => $row['limit_type'],
|
|
'bought_times' => $boughtTimes,
|
|
'total_buy_times' => $row['limit_num'],
|
|
); {
|
|
$priceInfo = mt\Item::getPriceInfo($itemMeta);
|
|
if (!empty($priceInfo)) {
|
|
$goodsDto['price_info'] = $priceInfo['price_info'];
|
|
}
|
|
}
|
|
$propertyChgService->addUserChg();
|
|
$this->_rspData(
|
|
array(
|
|
'award' => $awardService->toDto(),
|
|
'property_chg' => $propertyChgService->toDto(),
|
|
'goods_chg' => $goodsDto
|
|
)
|
|
);
|
|
break;
|
|
case ShopController::TOKEN_TYPE_CEG:
|
|
case ShopController::TOKEN_TYPE_CEC:
|
|
if ($isFreeBuy) {
|
|
$propertyChgService = new services\PropertyChgService();
|
|
$this->addFreeBuyRecord($row);
|
|
$itemMeta = mt\Item::get($row['goods_id']);
|
|
$this->internalAddItem($propertyChgService, $itemMeta, $goods_count, 1);
|
|
$this->_rspOk();
|
|
} else {
|
|
$price = $this->normalizeWeb3Price($goods_num * $need_price);
|
|
$item_id = $row['goods_id'];
|
|
$item_count = $goods_num;
|
|
|
|
$response = services\BlockChainService::gameItemMallBuy(
|
|
Transaction::BUY_GOODS_ACTION_TYPE,
|
|
$price,
|
|
$item_id,
|
|
$item_count
|
|
);
|
|
|
|
BcOrder::upsert($response['trans_id'], array(
|
|
'item_id' => $item_id,
|
|
'item_num' => $item_count,
|
|
'order_type' => 1,
|
|
'price' => $goods_num * $need_price,
|
|
'ext_data' => json_encode(array(
|
|
'mode' => SHOP_BUY_MODE_NORMAL,
|
|
'shop_id' => $row['shop_id'],
|
|
'id' => $id,
|
|
)),
|
|
));
|
|
|
|
$response['item_id'] = $item_id;
|
|
$response['item_num'] = $item_count;
|
|
|
|
error_log("buy normal, item_id = " . $item_id . " item_count = " . $item_count . " need_price = " . $need_price . " price = " . $price . " response = " . json_encode($response));
|
|
|
|
$this->_rspData(
|
|
array(
|
|
"block_chain" => $response
|
|
)
|
|
);
|
|
}
|
|
break;
|
|
|
|
case ShopController::TOKEN_TYPE_BCEG:
|
|
break;
|
|
|
|
case ShopController::TOKEN_TYPE_USDT:
|
|
case ShopController::TOKEN_TYPE_USDC:
|
|
case ShopController::TOKEN_TYPE_BUSD:
|
|
case ShopController::TOKEN_TYPE_MATIC:
|
|
case ShopController::TOKEN_TYPE_BNB:
|
|
default:
|
|
$this->_rspErr(1, "token_type is unsupport, {$token_type}");
|
|
}
|
|
}
|
|
|
|
public function buyDiamond()
|
|
{
|
|
$num = getReqVal('num', 0);
|
|
$price = $this->normalizeWeb3Price($num);
|
|
$item_id = V_ITEM_DIAMOND;
|
|
$item_count = $num;
|
|
|
|
error_log("buy diamond start " . $num);
|
|
|
|
$response = services\BlockChainService::gameItemMallBuy(
|
|
Transaction::BUY_GOODS_ACTION_TYPE,
|
|
$price,
|
|
$item_id,
|
|
$item_count
|
|
);
|
|
|
|
BcOrder::upsert($response['trans_id'], array(
|
|
'item_id' => $item_id,
|
|
'item_num' => $item_count,
|
|
'order_type' => 1,
|
|
'price' => $num,
|
|
'ext_data' => json_encode(array(
|
|
'mode' => SHOP_BUY_MODE_NORMAL,
|
|
)),
|
|
));
|
|
|
|
$response['item_id'] = $item_id;
|
|
$response['item_num'] = $item_count;
|
|
|
|
error_log("buy diamond, item_id = " . $item_id . " item_count = " . $item_count . " num = " . $num . " price = " . $price . " response = " . json_encode($response));
|
|
|
|
$this->_rspData(
|
|
array(
|
|
"block_chain" => $response
|
|
)
|
|
);
|
|
}
|
|
|
|
public function buyGoodsDS()
|
|
{
|
|
$idx = getReqVal('idx', 0);
|
|
$grid = getReqVal('grid', 0);
|
|
$count = getReqVal('count', 0);
|
|
|
|
if ($grid < 1 || $grid > 6) {
|
|
$this->_rspErr(2, 'grid is invalid');
|
|
return;
|
|
}
|
|
|
|
$conn = $this->_getMysql('');
|
|
|
|
$row = SqlHelper::selectOne(
|
|
$conn,
|
|
't_shop_dailyselection',
|
|
array(
|
|
'idx',
|
|
'address',
|
|
'grid_' . $grid,
|
|
'count_' . $grid,
|
|
),
|
|
array('idx' => $idx)
|
|
);
|
|
|
|
if (!$row) {
|
|
$this->_rspErr(2, 'idx is invalid');
|
|
return;
|
|
}
|
|
|
|
if ($row['grid_' . $grid] == 0) {
|
|
$this->_rspErr(2, 'grid is invalid');
|
|
return;
|
|
}
|
|
|
|
if ($row['count_' . $grid] < $count) {
|
|
$this->_rspErr(2, 'count is invalid');
|
|
return;
|
|
}
|
|
|
|
$sel_id = $row['grid_' . $grid];
|
|
|
|
$goods = mt\Dailyselection::get($sel_id);
|
|
|
|
$token_type = $goods['token_type'];
|
|
$costItemId = $this->getCostItemIdByTokenType($token_type);
|
|
|
|
$costItems = $this->makeCostItems($costItemId, $goods['goods_num'] * $count * $goods['price']);
|
|
$lackItem = null;
|
|
if (!$this->_hasEnoughItems($costItems, $lackItem)) {
|
|
$this->_rspErr(2, $this->_getLackItemErrMsg($lackItem));
|
|
return;
|
|
}
|
|
|
|
|
|
$item_id = $goods['goods_id'];
|
|
$item_num = $goods['goods_num'] * $count;
|
|
|
|
$sql = "UPDATE t_shop_dailyselection SET count_$grid = count_$grid - $count WHERE idx = $idx";
|
|
$chk = $conn->execScript($sql);
|
|
|
|
$itemMeta = mt\Item::get($item_id);
|
|
$propertyChgService = new services\PropertyChgService();
|
|
for ($i = 0; $i < $count; $i++) {
|
|
$this->internalAddItem($propertyChgService, $itemMeta, $item_num, 0);
|
|
}
|
|
$awardService = new services\AwardService();
|
|
$awardService->addItem($goods['goods_id'], $count);
|
|
|
|
$this->_decItems($costItems);
|
|
$event = [
|
|
'name' => LogService::SHOP_BUY_ITEM_DAILY,
|
|
'val' => $costItems[0]['item_num']
|
|
];
|
|
LogService::consumeDiamond($event);
|
|
|
|
$goodsDto = array(
|
|
'goods_id' => $sel_id,
|
|
'item_id' => $goods['goods_id'],
|
|
'price_info' => array(
|
|
'item_id' => $goods['goods_id'],
|
|
'cost_list' => array(),
|
|
),
|
|
'bought_times' => 0,
|
|
'total_buy_times' => 0,
|
|
); {
|
|
$priceInfo = mt\Item::getPriceInfo($itemMeta);
|
|
if (!empty($priceInfo)) {
|
|
$goodsDto['price_info'] = $priceInfo['price_info'];
|
|
}
|
|
}
|
|
$propertyChgService->addUserChg();
|
|
|
|
$this->_rspData(
|
|
array(
|
|
'idx' => $idx,
|
|
'grid' => $grid,
|
|
'count' => $count,
|
|
'award' => $awardService->toDto(),
|
|
)
|
|
);
|
|
}
|
|
|
|
private function buyGoodsDSOld()
|
|
{
|
|
$account = $this->_getAccountId();
|
|
$address = $this->_getAddress();
|
|
if (empty($address)) {
|
|
$this->_rspErr(5, 'address is empty');
|
|
return;
|
|
}
|
|
|
|
$idx = getReqVal('idx', 0);
|
|
$grid = getReqVal('grid', 0);
|
|
$count = getReqVal('count', 0);
|
|
|
|
$conn = $this->_getMysql('');
|
|
|
|
$row = SqlHelper::selectOne(
|
|
$conn,
|
|
't_shop_dailyselection',
|
|
array(
|
|
'idx',
|
|
'address',
|
|
'grid_' . $grid,
|
|
'count_' . $grid,
|
|
),
|
|
array('idx' => $idx)
|
|
);
|
|
|
|
if (!$row) {
|
|
$this->_rspErr(2, 'idx is invalid');
|
|
return;
|
|
}
|
|
|
|
if ($row['grid_' . $grid] == 0) {
|
|
$this->_rspErr(2, 'grid is invalid');
|
|
return;
|
|
}
|
|
|
|
if ($row['count_' . $grid] < $count) {
|
|
$this->_rspErr(2, 'count is invalid');
|
|
return;
|
|
}
|
|
|
|
$sel_id = $row['grid_' . $grid];
|
|
|
|
$goods = mt\Dailyselection::get($sel_id);
|
|
|
|
$pending = $this->checkPendingBuyGoodsDS($address, $goods['goods_id'], $idx, $grid);
|
|
if ($pending) {
|
|
$this->_rspErr(2, 'pending');
|
|
return;
|
|
}
|
|
|
|
$price = $this->normalizeWeb3Price($goods['price'] * $count);
|
|
$item_id = $goods['goods_id'];
|
|
$item_count = $goods['goods_num'] * $count;
|
|
error_log("buyGoodsDS start " . json_encode(
|
|
array(
|
|
'idx' => $idx,
|
|
'grid' => $grid,
|
|
'count' => $count,
|
|
'goodPrice' => $goods['price'],
|
|
'price' => $price,
|
|
'item_id' => $item_id,
|
|
'item_count' => $item_count,
|
|
)
|
|
));
|
|
$response = services\BlockChainService::gameItemMallBuy(
|
|
Transaction::BUY_GOODS_ACTION_TYPE,
|
|
$price,
|
|
$item_id,
|
|
$item_count
|
|
);
|
|
|
|
BcOrder::upsert($response['trans_id'], array(
|
|
'item_id' => $item_id,
|
|
'item_num' => $item_count,
|
|
'order_type' => 1,
|
|
'price' => $goods['price'] * $count,
|
|
'ext_data' => json_encode(array(
|
|
'mode' => SHOP_BUY_MODE_DAILY_SELECTION,
|
|
'idx' => $idx,
|
|
'grid' => $grid,
|
|
'count' => $count,
|
|
)),
|
|
));
|
|
|
|
error_log("buyGoodsDS start " . json_encode(
|
|
array(
|
|
'idx' => $idx,
|
|
'grid' => $grid,
|
|
'count' => $count,
|
|
'block_chain' => $response,
|
|
)
|
|
));
|
|
|
|
$this->_rspData(
|
|
array(
|
|
'idx' => $idx,
|
|
'grid' => $grid,
|
|
'count' => $count,
|
|
'block_chain' => $response,
|
|
)
|
|
);
|
|
}
|
|
|
|
private function openBlindBox()
|
|
{
|
|
$account = $this->_getAccountId();
|
|
|
|
$item_id = getReqVal('item_id', 0);
|
|
$meta = mt\Item::get($item_id);
|
|
$box = Bag::find($item_id);
|
|
error_log('openBlindBox ' . json_encode($box) . ' ' . $item_id . ' ' . $meta['sub_type']);
|
|
if (!$box) {
|
|
$this->_rspErr(2, 'item_id is invalid');
|
|
return;
|
|
}
|
|
|
|
$num = $box['item_num'];
|
|
if ($num < 1) {
|
|
$this->_rspErr(2, 'num is invalid');
|
|
return;
|
|
}
|
|
|
|
$itemStore = mt\ShopChest::getRandomItemListByChestType($meta['sub_type']);
|
|
$result = array();
|
|
Bag::decItem($item_id, $num);
|
|
for ($i = 0; $i < $num; $i++) {
|
|
$record = array();
|
|
foreach ($itemStore as $key => $value) {
|
|
$item = $this->weighted_random($value);
|
|
$itemMeta = mt\Item::get($item['item_id']);
|
|
$propertyChgService = new services\PropertyChgService();
|
|
if ($item['item_type'] == 2) {
|
|
$this->internalAddItem($propertyChgService, $itemMeta, $item['num'], 1);
|
|
} else {
|
|
for ($j = 0; $j < $item['num']; $j++) {
|
|
$this->internalAddItem($propertyChgService, $itemMeta, 1, 1);
|
|
}
|
|
}
|
|
$record[$key] = array("item_id" => $item['item_id'], "item_num" => $item['num']);
|
|
array_push($result, $record[$key]);
|
|
}
|
|
}
|
|
|
|
error_log("openBlindBox start " . json_encode(
|
|
array(
|
|
'account' => $account,
|
|
'item_id' => $item_id,
|
|
'num' => $num,
|
|
'items' => $result,
|
|
)
|
|
));
|
|
|
|
$this->_rspData(
|
|
array(
|
|
'items' => $result,
|
|
)
|
|
);
|
|
}
|
|
|
|
public function getChestItems()
|
|
{
|
|
// $address = $this->_getAddress();
|
|
// if (!$address) {
|
|
// $this->_rspErr(2, 'address is invalid');
|
|
// return;
|
|
// }
|
|
|
|
$id = getReqVal('id', 0);
|
|
$goods = mt\ShopGoods::get($id);
|
|
$goods_id = $goods['goods_id'];
|
|
$shop_id = $goods['shop_id'];
|
|
|
|
$meta = mt\Item::get($goods_id);
|
|
if ($meta['type'] != mt\Item::CHEST_BOX_TYPE) {
|
|
$this->_rspErr(2, 'goods_id is invalid');
|
|
return;
|
|
}
|
|
$chestType = $meta['sub_type'];
|
|
$itemStore = mt\ShopChest::getRandomItemListByChestType($chestType);
|
|
if (!$itemStore) {
|
|
$this->_rspErr(2, 'goods_id is invalid');
|
|
return;
|
|
}
|
|
error_log("getChestItems start1 " . json_encode(
|
|
array(
|
|
'goods_id' => $goods_id,
|
|
'chestType' => $chestType,
|
|
'items' => $itemStore,
|
|
)
|
|
));
|
|
$record = array();
|
|
foreach ($itemStore as $key => $value) {
|
|
foreach ($value as $k => $v) {
|
|
if (empty($record[$v['item_id']])) {
|
|
$record[$v['item_id']] = 0;
|
|
}
|
|
$record[$v['item_id']] += 1;
|
|
}
|
|
}
|
|
|
|
if (!empty($goods['free_type'])) {
|
|
$count = $this->countFreeBuyTimes($goods['free_type'], $goods['id'], $goods['goods_id']);
|
|
$goods['free_num'] = $goods['free_num'] - $count;
|
|
} else {
|
|
$goods['free_num'] = 0;
|
|
}
|
|
|
|
$free_num = $goods['free_num'];
|
|
// $pending = $this->checkPendingBuyGoodsNormal($address, $goods_id, $shop_id, $id);
|
|
error_log("getChestItems start " . json_encode(
|
|
array(
|
|
'goods_id' => $goods_id,
|
|
'items' => array_keys($record),
|
|
'free_num' => $free_num,
|
|
'pending' => 0,
|
|
)
|
|
));
|
|
|
|
$this->_rspData(
|
|
array(
|
|
'items' => array_keys($record),
|
|
'free_num' => $free_num,
|
|
'pending' => 0,
|
|
)
|
|
);
|
|
}
|
|
|
|
private function getMyBlindBoxs()
|
|
{
|
|
|
|
$itemDb = Bag::getAllByType(mt\Item::CHEST_BOX_TYPE);
|
|
$items = array();
|
|
foreach ($itemDb as $key => $value) {
|
|
array_push($items, $value['item_id']);
|
|
}
|
|
|
|
$this->_rspData(
|
|
array(
|
|
'items' => $items,
|
|
)
|
|
);
|
|
}
|
|
|
|
private function getCostItemIdByTokenType($token_type)
|
|
{
|
|
switch ($token_type) {
|
|
case ShopController::TOKEN_TYPE_GOLD:
|
|
return V_ITEM_GOLD;
|
|
break;
|
|
|
|
case ShopController::TOKEN_TYPE_DIAMOND:
|
|
return V_ITEM_DIAMOND;
|
|
break;
|
|
|
|
case ShopController::TOKEN_TYPE_CEG:
|
|
case ShopController::TOKEN_TYPE_BCEG:
|
|
case ShopController::TOKEN_TYPE_USDT:
|
|
case ShopController::TOKEN_TYPE_USDC:
|
|
case ShopController::TOKEN_TYPE_BUSD:
|
|
case ShopController::TOKEN_TYPE_MATIC:
|
|
case ShopController::TOKEN_TYPE_BNB:
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
private function makeCostItems($item_id, $num)
|
|
{
|
|
$costItems = array(
|
|
array(
|
|
'item_id' => $item_id,
|
|
'item_num' => $num
|
|
)
|
|
);
|
|
return $costItems;
|
|
}
|
|
|
|
private function buyGoodsFree()
|
|
{
|
|
}
|
|
|
|
private function decDailySelectionItem($idx, $grid, $count)
|
|
{
|
|
$self = myself();
|
|
if (!$self) return false;
|
|
|
|
$conn = $self->_getMysql('');
|
|
$sql = "SELECT count_$grid FROM t_shop_dailyselection WHERE idx = $idx";
|
|
$chk = $conn->execQuery($sql);
|
|
if (!$chk) return false;
|
|
if ($chk[0]['count_' . $grid] < $count) return false;
|
|
|
|
$sql = "UPDATE t_shop_dailyselection SET count_$grid = count_$grid - $count WHERE idx = $idx";
|
|
$chk = $conn->execScript($sql);
|
|
return $chk;
|
|
}
|
|
|
|
private function clearBeforeTodayDailySelections()
|
|
{
|
|
$self = myself();
|
|
if (!$self) return;
|
|
|
|
$conn = $self->_getMysql('');
|
|
$nowTime = $this->_getNowTime();
|
|
$dayTime = $this->_getDaySeconds($nowTime);
|
|
|
|
$sql = "DELETE FROM t_shop_dailyselection WHERE refresh_time < $dayTime";
|
|
$chk = $conn->execScript($sql);
|
|
return $chk;
|
|
}
|
|
|
|
private function countTodayRefreshTimes($address)
|
|
{
|
|
$self = myself();
|
|
if (!$self) return;
|
|
|
|
$conn = $self->_getMysql('');
|
|
$nowTime = $this->_getNowTime();
|
|
$dayTime = $this->_getDaySeconds($nowTime);
|
|
|
|
$sql = "SELECT COUNT(*) AS cnt FROM t_shop_dailyselection WHERE address = '$address' AND refresh_mode = 1 AND refresh_time >= $dayTime";
|
|
|
|
$row = $conn->execQuery($sql);
|
|
|
|
return $row[0]['cnt'];
|
|
}
|
|
|
|
private function getTodayLastDailySelection($address)
|
|
{
|
|
$self = myself();
|
|
if (!$self) return;
|
|
|
|
$conn = $self->_getMysql('');
|
|
$nowTime = $this->_getNowTime();
|
|
$dayTime = $this->_getDaySeconds($nowTime);
|
|
|
|
$sql = "SELECT * FROM t_shop_dailyselection WHERE address = '$address' AND refresh_time >= $dayTime ORDER BY idx DESC LIMIT 1";
|
|
|
|
$row = $conn->execQuery($sql);
|
|
|
|
return $row;
|
|
}
|
|
|
|
private function refreshDailySelectionWithMode($address, $mode)
|
|
{
|
|
$selection = $this->randomNewDailySelection();
|
|
|
|
$self = myself();
|
|
if (!$self) return;
|
|
|
|
$conn = $self->_getMysql('');
|
|
$nowTime = $this->_getNowTime();
|
|
|
|
$chk = SqlHelper::insert(
|
|
$conn,
|
|
't_shop_dailyselection',
|
|
array(
|
|
'address' => $address,
|
|
'refresh_mode' => $mode,
|
|
'refresh_time' => $nowTime,
|
|
'grid_1' => $selection[1]['id'],
|
|
'grid_2' => $selection[2]['id'],
|
|
'grid_3' => $selection[3]['id'],
|
|
'grid_4' => $selection[4]['id'],
|
|
'grid_5' => $selection[5]['id'],
|
|
'grid_6' => $selection[6]['id'],
|
|
'count_1' => 1,
|
|
'count_2' => 1,
|
|
'count_3' => 1,
|
|
'count_4' => 1,
|
|
'count_5' => 1,
|
|
'count_6' => 1,
|
|
)
|
|
);
|
|
|
|
return $chk;
|
|
}
|
|
|
|
private function randomNewDailySelection()
|
|
{
|
|
$newDailySelection = array();
|
|
for ($i = 1; $i <= 6; $i++) {
|
|
$store = mt\Dailyselection::getBySlot($i);
|
|
$newDailySelection[$i] = $this->weighted_random($store);
|
|
}
|
|
return $newDailySelection;
|
|
}
|
|
|
|
private function weighted_random($array)
|
|
{
|
|
// 计算数组元素的总权重
|
|
$total_weight = array_sum(array_column($array, "weight"));
|
|
// 生成一个随机数
|
|
$rand = mt_rand(1, $total_weight);
|
|
// 遍历数组,找到随机数对应的元素
|
|
foreach ($array as $item) {
|
|
// 如果随机数小于或等于当前元素的权重,返回该元素
|
|
if ($rand <= $item["weight"]) {
|
|
return $item;
|
|
}
|
|
// 否则,减去当前元素的权重,继续循环
|
|
$rand -= $item["weight"];
|
|
}
|
|
}
|
|
|
|
private function countBuyGoodsRequestTimesByGoodsId($address, $goodsId)
|
|
{
|
|
$self = myself();
|
|
if (!$self) return;
|
|
|
|
$conn = $self->_getMysql('');
|
|
|
|
$sql = "SELECT COUNT(*) AS cnt FROM t_bc_order WHERE address = '$address' AND item_id = '$goodsId'";
|
|
|
|
$row = $conn->execQuery($sql);
|
|
|
|
return $row[0]['cnt'];
|
|
}
|
|
|
|
private function checkPendingBuyGoodsNormal($address, $goodsId, $shop_id, $id)
|
|
{
|
|
$self = myself();
|
|
if (!$self) return;
|
|
|
|
$conn = $self->_getMysql('');
|
|
|
|
$rows = SqlHelper::select(
|
|
$conn,
|
|
't_bc_order',
|
|
array('ext_data', 'createtime'),
|
|
array(
|
|
'address' => $address,
|
|
'item_id' => $goodsId,
|
|
'status' => 0,
|
|
)
|
|
);
|
|
foreach ($rows as $row) {
|
|
if ($row['createtime'] + 15 * 60 < $self->_getNowTime()) continue; // 15分钟内有效
|
|
$extData = json_decode($row['ext_data'], true);
|
|
// error_log("checkPendingBuyGoodsNormal: " . json_encode($extData));
|
|
if ($extData['mode'] == SHOP_BUY_MODE_NORMAL) {
|
|
if ($extData['shop_id'] == $shop_id) {
|
|
if ($extData['id'] == $id) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private function checkPendingBuyGoodsDS($address, $goodsId, $idx, $grid)
|
|
{
|
|
$self = myself();
|
|
if (!$self) return;
|
|
|
|
$conn = $self->_getMysql('');
|
|
|
|
$rows = SqlHelper::select(
|
|
$conn,
|
|
't_bc_order',
|
|
array('ext_data', 'createtime'),
|
|
array(
|
|
'address' => $address,
|
|
'item_id' => $goodsId,
|
|
'status' => 0,
|
|
)
|
|
);
|
|
foreach ($rows as $row) {
|
|
if ($row['createtime'] + 15 * 60 < $self->_getNowTime()) continue; // 15分钟内有效
|
|
$extData = json_decode($row['ext_data'], true);
|
|
if ($extData['mode'] == SHOP_BUY_MODE_DAILY_SELECTION) {
|
|
if ($extData['idx'] == $idx) {
|
|
if ($extData['grid'] == $grid) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
private function outsideBuy($shopId, $itemId, $itemNum, $costItemId)
|
|
{
|
|
$propertyChgService = new services\PropertyChgService();
|
|
$itemMeta = mt\Item::get($itemId);
|
|
if (!$itemMeta) {
|
|
$this->_rspErr(1, 'item_id parameter error');
|
|
return;
|
|
}
|
|
if ($itemNum != 1) {
|
|
$this->_rspErr(1, 'the item_num parameter must be equal to 1');
|
|
return;
|
|
}
|
|
$costItemMeta = mt\Item::get($costItemId);
|
|
if (!$costItemMeta) {
|
|
$this->_rspErr(1, 'cost_item_id parameter error');
|
|
return;
|
|
}
|
|
$types = array(
|
|
mt\Item::HERO_TYPE,
|
|
mt\Item::HERO_SKIN_TYPE,
|
|
mt\Item::GUN_SKIN_TYPE
|
|
);
|
|
if (!mt\Item::inTypes($itemMeta, $types)) {
|
|
$this->_rspErr(1, 'item_id parameter error');
|
|
return;
|
|
} {
|
|
$errCode = 0;
|
|
$errMsg = '';
|
|
if (!$this->canBuy($itemMeta, $errCode, $errMsg)) {
|
|
$this->_rspErr($errCode, $errMsg);
|
|
return;
|
|
}
|
|
}
|
|
$priceInfo = mt\Item::getPriceInfo($itemMeta);
|
|
if (empty($priceInfo)) {
|
|
$this->_rspErr(2, 'config error');
|
|
return;
|
|
}
|
|
$costItems = $this->getCostItems($priceInfo, $costItemId);
|
|
if (empty($costItems)) {
|
|
$this->_rspErr(2, 'config error2');
|
|
return;
|
|
}
|
|
$lackItem = null;
|
|
if (!$this->_hasEnoughItems($costItems, $lackItem)) {
|
|
$this->_rspErr(3, $this->_getLackItemErrMsg($lackItem));
|
|
return;
|
|
}
|
|
$this->_decItems($costItems);
|
|
$this->internalAddItem($propertyChgService, $itemMeta, 1, 0);
|
|
$awardService = new services\AwardService();
|
|
$awardService->addItem($itemId, $itemNum);
|
|
ShopBuyRecord::add($itemId, $itemNum);
|
|
$goodsDto = array(
|
|
'goods_id' => $itemMeta['id'],
|
|
'item_id' => $itemMeta['id'],
|
|
'price_info' => array(
|
|
'item_id' => $itemMeta['id'],
|
|
'cost_list' => array(),
|
|
'discount_begin_time' => phpcommon\datetimeToTimestamp($itemMeta['discount_begin']),
|
|
'discount_end_time' => phpcommon\datetimeToTimestamp($itemMeta['discount_end'])
|
|
),
|
|
'flag_icon' => '',
|
|
'limit_type' => $itemMeta['limit_type'],
|
|
'bought_times' => 0,
|
|
'total_buy_times' => $itemMeta['limit_num'],
|
|
); {
|
|
$priceInfo = mt\Item::getPriceInfo($itemMeta);
|
|
if (!empty($priceInfo)) {
|
|
$goodsDto['price_info'] = $priceInfo;
|
|
}
|
|
}
|
|
$propertyChgService->addUserChg();
|
|
$this->_rspData(
|
|
array(
|
|
'award' => $awardService->toDto(),
|
|
'property_chg' => $propertyChgService->toDto(),
|
|
'goods_chg' => $goodsDto
|
|
)
|
|
);
|
|
}
|
|
|
|
private function getOutsideShopInfo()
|
|
{
|
|
$items = array(); {
|
|
$types = array(
|
|
mt\Item::HERO_TYPE,
|
|
mt\Item::HERO_SKIN_TYPE,
|
|
mt\Item::GUN_SKIN_TYPE
|
|
);
|
|
mt\Item::filter(function ($meta) use (&$items, &$types) {
|
|
if (mt\Item::inTypes($meta, $types)) {
|
|
array_push($items, $meta);
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
$goodsDtoList1 = array();
|
|
$goodsDtoList2 = array();
|
|
array_walk($items, function ($val) use (&$priceList, &$goodsDtoList1, &$goodsDtoList2) {
|
|
$goodsDto = array(
|
|
'goods_id' => $val['id'],
|
|
'item_id' => $val['id'],
|
|
'price_info' => null,
|
|
'flag_icon' => '',
|
|
'limit_type' => $val['limit_type'],
|
|
'bought_times' => 0,
|
|
'total_buy_times' => $val['limit_num'],
|
|
);
|
|
$priceInfo = mt\Item::getPriceInfo($val);
|
|
if (!empty($priceInfo)) {
|
|
$goodsDto['price_info'] = $priceInfo['price_info'];
|
|
array_push($goodsDtoList1, $goodsDto);
|
|
}
|
|
});
|
|
$this->_rspData(
|
|
array(
|
|
'info' => array(
|
|
'shop_id' => mt\Shop::OUTSIDE_SHOP,
|
|
'goods_list1' => $goodsDtoList1,
|
|
'goods_list2' => $goodsDtoList2,
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
private function getCostItems($priceInfo, $costItemId)
|
|
{
|
|
$costGroup = null;
|
|
array_walk($priceInfo['price_info']['cost_list'], function ($val) use (&$costGroup, $costItemId) {
|
|
if ($costGroup) {
|
|
return;
|
|
}
|
|
if (count($val) > 0 && $val[0]['item_id'] == $costItemId) {
|
|
$costGroup = $val;
|
|
return;
|
|
}
|
|
});
|
|
if (!$costGroup) {
|
|
return null;
|
|
}
|
|
$costItems = array();
|
|
array_walk($costGroup, function ($val) use (&$costItems, $priceInfo) {
|
|
if (
|
|
$val['discount'] > 0 &&
|
|
$this->_getNowTime() >= $priceInfo['discount_begin_time'] &&
|
|
$this->_getNowTime() <= $priceInfo['discount_end_time']
|
|
) {
|
|
array_push(
|
|
$costItems,
|
|
array(
|
|
'item_id' => $val['item_id'],
|
|
'item_num' => (int) ($val['item_num'] * ($priceInfo['discount'] / 100)),
|
|
)
|
|
);
|
|
} else {
|
|
array_push(
|
|
$costItems,
|
|
array(
|
|
'item_id' => $val['item_id'],
|
|
'item_num' => $val['item_num'],
|
|
)
|
|
);
|
|
}
|
|
});
|
|
return $costItems;
|
|
}
|
|
|
|
private function internalAddItem($propertyChgService, $itemMeta, $count, $sysAdd)
|
|
{
|
|
switch ($itemMeta['type']) {
|
|
case mt\Item::HERO_TYPE: {
|
|
Hero::addHero($itemMeta);
|
|
$propertyChgService->addHeroChg();
|
|
$propertyChgService->addUserChg();
|
|
}
|
|
break;
|
|
case mt\Item::HERO_SKIN_TYPE: {
|
|
HeroSkin::addSkin($itemMeta);
|
|
$propertyChgService->addHeroSkinChg();
|
|
}
|
|
break;
|
|
case mt\Item::GUN_TYPE: {
|
|
Gun::addGun($itemMeta);
|
|
$propertyChgService->addGunChg();
|
|
}
|
|
break;
|
|
case mt\Item::GUN_SKIN_TYPE: {
|
|
GunSkin::addSkin($itemMeta);
|
|
$propertyChgService->addGunSkinChg();
|
|
}
|
|
break;
|
|
case mt\Item::CHIP_TYPE: {
|
|
Chip::addChip($itemMeta);
|
|
$propertyChgService->addChip();
|
|
}
|
|
break;
|
|
default: {
|
|
if ($this->_isVirtualItem($itemMeta['id'])) {
|
|
$this->_addVirtualItem($itemMeta['id'], $count, null, $propertyChgService);
|
|
$propertyChgService->addUserChg();
|
|
// 充值就尝试开启首充活动
|
|
if ($sysAdd != 1) {
|
|
if ($itemMeta['id'] == 10001) {
|
|
$this->beginFirstTupop();
|
|
}
|
|
}
|
|
} else {
|
|
Bag::addItem($itemMeta['id'], $count);
|
|
$propertyChgService->addBagChg();
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private function canBuy($itemMeta, &$errCode, &$errMsg)
|
|
{
|
|
$errCode = 0;
|
|
$errMsg = '';
|
|
switch ($itemMeta['type']) {
|
|
case mt\Item::HERO_TYPE: {
|
|
$heroDb = Hero::find($itemMeta['id']);
|
|
if ($heroDb) {
|
|
$errCode = 10;
|
|
$errMsg = 'You already have the hero';
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
case mt\Item::HERO_SKIN_TYPE: {
|
|
$heroSkinDb = HeroSkin::find($itemMeta['id']);
|
|
if ($heroSkinDb) {
|
|
$errCode = 10;
|
|
$errMsg = 'You already have the skin';
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
case mt\Item::GUN_SKIN_TYPE: {
|
|
$gunSkinDb = GunSkin::find($itemMeta['id']);
|
|
if ($gunSkinDb) {
|
|
$errCode = 10;
|
|
$errMsg = 'You already have the skin';
|
|
return false;
|
|
}
|
|
}
|
|
break;
|
|
default: {
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private function beginFirstTupop()
|
|
{
|
|
$conn = myself()->_getMysql('');
|
|
|
|
$exist = SqlHelper::selectOne(
|
|
$conn,
|
|
't_first_topup',
|
|
array('address'),
|
|
array('address' => myself()->_getAddress())
|
|
);
|
|
if ($exist) {
|
|
return;
|
|
}
|
|
|
|
// 开始首充奖励活动进程
|
|
$chk = SqlHelper::insert(
|
|
$conn,
|
|
't_first_topup',
|
|
array(
|
|
'address' => myself()->_getAddress(),
|
|
'createtime' => myself()->_getNowTime(),
|
|
'status1' => 0,
|
|
'status2' => 0,
|
|
'status3' => 0,
|
|
)
|
|
);
|
|
if (!$chk) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
private function lastInsertId($conn)
|
|
{
|
|
$row = $conn->execQueryOne('SELECT LAST_INSERT_ID() as lastId;', array());
|
|
return $row['lastId'];
|
|
}
|
|
|
|
private function normalizeWeb3Price($price)
|
|
{
|
|
$bn1 = phpcommon\bnInit($price * pow(10, 8));
|
|
$bn2 = phpcommon\bnInit('1000000000000000000');
|
|
$ret_price = phpcommon\bnDiv(phpcommon\bnMul($bn1, $bn2), pow(10, 8));
|
|
|
|
// error_log('normalizeWeb3Price: ' . $ret_price . ' ' . $price * pow(10, 8));
|
|
return phpcommon\bnToStr($ret_price);
|
|
}
|
|
|
|
private function countFreeBuyTimes($free_type, $id, $goods_id)
|
|
{
|
|
$conn = myself()->_getMysql('');
|
|
$account = myself()->_getAccountId();
|
|
|
|
switch ($free_type) {
|
|
case 1: {
|
|
$dayTime = myself()->_getNowDaySeconds();
|
|
$sql = 'SELECT COUNT(*) as cnt FROM t_shop_free_record WHERE account_id = ? AND `id` = ? AND goods_id = ? AND createtime >= ?';
|
|
$row = $conn->execQueryOne($sql, array($account, $id, $goods_id, $dayTime));
|
|
return $row['cnt'];
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
private function addFreeBuyRecord($goods)
|
|
{
|
|
$conn = myself()->_getMysql('');
|
|
$account = myself()->_getAccountId();
|
|
|
|
switch ($goods['free_type']) {
|
|
case 1: {
|
|
$dayTime = myself()->_getNowTime();
|
|
SqlHelper::insert(
|
|
$conn,
|
|
't_shop_free_record',
|
|
array(
|
|
'account_id' => $account,
|
|
'shop_id' => $goods['shop_id'],
|
|
'id' => $goods['id'],
|
|
'goods_id' => $goods['goods_id'],
|
|
'goods_num' => $goods['goods_num'],
|
|
'free_type' => $goods['free_type'],
|
|
'free_num' => $goods['free_num'],
|
|
'createtime' => $dayTime,
|
|
)
|
|
);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
private function buyGoodsNew()
|
|
{
|
|
$id = getReqVal('id', 0);
|
|
$token_type = getReqVal('token_type', '');
|
|
$goods_num = getReqVal('goods_num', 0);
|
|
|
|
$row = mt\ShopGoods::get($id);
|
|
|
|
$desired_token_type = $row['token_type'];
|
|
$check_token_type = splitStr1($desired_token_type);
|
|
$token_pos = array_search($token_type, $check_token_type, true);
|
|
if (!in_array($token_type, $check_token_type)) {
|
|
$this->_rspErr(1, "token_type parameter error, desired_token_type: {$desired_token_type}");
|
|
return;
|
|
}
|
|
|
|
if ($goods_num > $row['max_amount']) {
|
|
$this->_rspErr(1, "goods_num parameter error, max_amount: {$row['max_amount']}");
|
|
return;
|
|
}
|
|
|
|
// 这里命名混乱了, 购买个数,一捆个数命名冲突
|
|
$goods_count = $row['goods_num'];
|
|
|
|
$buyRecordHash = ShopBuyRecord::allToHash();
|
|
$boughtTimes = 1;
|
|
switch ($row['limit_type']) {
|
|
case ShopController::DAILY_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $id);
|
|
$boughtTimes = $buyRecord ? $buyRecord['this_day_buy_times'] + 1 : 1;
|
|
if ($buyRecord && getXVal($buyRecord, 'this_day_buy_times', 0) >= $row['limit_num']) {
|
|
$this->_rspErr(2, 'Has reached the maximum number of purchase restrictions today');
|
|
return;
|
|
}
|
|
if ($row['limit_num'] <= 0) {
|
|
$this->_rspErr(2, 'The maximum number of purchase restrictions has been reached');
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case ShopController::WEEKLY_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $id);
|
|
$boughtTimes = $buyRecord ? $buyRecord['this_week_buy_times'] + 1 : 1;
|
|
if ($buyRecord && getXVal($buyRecord, 'this_week_buy_times', 0) >= $row['limit_num']) {
|
|
$this->_rspErr(2, 'The maximum number of purchase restrictions this week has been reached');
|
|
return;
|
|
}
|
|
if ($row['limit_num'] <= 0) {
|
|
$this->_rspErr(2, 'The maximum number of purchase restrictions has been reached');
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case ShopController::TOTAL_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $id);
|
|
$boughtTimes = $buyRecord ? $buyRecord['total_buy_times'] + 1 : 1;
|
|
if ($buyRecord && getXVal($buyRecord, 'total_buy_times', 0) >= $row['limit_num']) {
|
|
$this->_rspErr(2, 'The maximum number of purchase restrictions has been reached');
|
|
return;
|
|
}
|
|
if ($row['limit_num'] <= 0) {
|
|
$this->_rspErr(2, 'he maximum number of purchase restrictions has been reached');
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
default: {
|
|
}
|
|
break;
|
|
}
|
|
|
|
$price_array = splitStr1($row['price']);
|
|
$discount_array = splitStr1($row['discount']);
|
|
|
|
$need_price = $price_array[$token_pos];
|
|
$discount = $discount_array[$token_pos];
|
|
|
|
$discount_begin = strtotime($row['discount_begin'] . ' UTC');
|
|
$discount_end = strtotime($row['discount_end'] . ' UTC');
|
|
$nowTime = $this->_getNowTime();
|
|
|
|
if ($nowTime >= $discount_begin && $nowTime < $discount_end) {
|
|
|
|
$need_price = ceil($need_price * ($discount / 100.0));
|
|
}
|
|
|
|
$costItemId = $this->getCostItemIdByTokenType($token_type);
|
|
|
|
switch ($token_type) {
|
|
case ShopController::TOKEN_TYPE_CEG:
|
|
case ShopController::TOKEN_TYPE_CEC:
|
|
$costItems = $this->makeCostItems($costItemId, $goods_num * $need_price);
|
|
$lackItem = null;
|
|
if (!$this->_hasEnoughItems($costItems, $lackItem)) {
|
|
$this->_rspErr(2, $this->_getLackItemErrMsg($lackItem));
|
|
return;
|
|
}
|
|
|
|
$itemMeta = mt\Item::get($row['goods_id']);
|
|
$propertyChgService = new services\PropertyChgService();
|
|
for ($i = 0; $i < $goods_num; $i++) {
|
|
$this->internalAddItem($propertyChgService, $itemMeta, $goods_count, 0);
|
|
}
|
|
$awardService = new services\AwardService();
|
|
$awardService->addItem($row['goods_id'], $goods_num);
|
|
ShopBuyRecord::add($id, $goods_num);
|
|
$this->_decItems($costItems);
|
|
$goodsDto = array(
|
|
'goods_id' => $id,
|
|
'item_id' => $row['goods_id'],
|
|
'price_info' => array(
|
|
'item_id' => $row['goods_id'],
|
|
'cost_list' => array(),
|
|
'discount_begin_time' => phpcommon\datetimeToTimestamp($row['discount_begin']),
|
|
'discount_end_time' => phpcommon\datetimeToTimestamp($row['discount_end'])
|
|
),
|
|
'flag_icon' => $row['tag'],
|
|
'limit_type' => $row['limit_type'],
|
|
'bought_times' => $boughtTimes,
|
|
'total_buy_times' => $row['limit_num'],
|
|
); {
|
|
$priceInfo = mt\Item::getPriceInfo($itemMeta);
|
|
if (!empty($priceInfo)) {
|
|
$goodsDto['price_info'] = $priceInfo['price_info'];
|
|
}
|
|
}
|
|
$propertyChgService->addUserChg();
|
|
$this->_rspData(
|
|
array(
|
|
'award' => $awardService->toDto(),
|
|
'property_chg' => $propertyChgService->toDto(),
|
|
'goods_chg' => $goodsDto
|
|
)
|
|
);
|
|
break;
|
|
|
|
case ShopController::TOKEN_TYPE_BCEG:
|
|
break;
|
|
|
|
case ShopController::TOKEN_TYPE_USDT:
|
|
case ShopController::TOKEN_TYPE_USDC:
|
|
case ShopController::TOKEN_TYPE_BUSD:
|
|
case ShopController::TOKEN_TYPE_MATIC:
|
|
case ShopController::TOKEN_TYPE_BNB:
|
|
default:
|
|
$this->_rspErr(1, "token_type is unsupport, {$token_type}");
|
|
}
|
|
}
|
|
|
|
public function buyBlindBox()
|
|
{
|
|
$account = $this->_getAccountId();
|
|
|
|
$id = getReqVal('id', 0);
|
|
$num = getReqVal('num', 0);
|
|
|
|
if (!($num == 1 || $num == 10)) {
|
|
$this->_rspErr(2, 'num is invalid');
|
|
return;
|
|
}
|
|
|
|
$shop = mt\ShopGoods::get($id);
|
|
if (!$shop) {
|
|
$this->_rspErr(2, 'id is invalid');
|
|
return;
|
|
}
|
|
$meta = mt\Item::get($shop['goods_id']);
|
|
$cost = $shop['price'] * $num;
|
|
$isFreeBuy = false;
|
|
if (!empty($shop['free_type'])) {
|
|
$count = $this->countFreeBuyTimes($shop['free_type'], $shop['id'], $shop['goods_id']);
|
|
if ($count < $shop['free_num']) {
|
|
$isFreeBuy = true;
|
|
}
|
|
}
|
|
if ($isFreeBuy) {
|
|
if ($num != 1) {
|
|
$this->_rspErr(2, 'num is invalid');
|
|
return;
|
|
}
|
|
} else {
|
|
$costItems = $this->makeCostItems(V_ITEM_DIAMOND, $num * $shop['price']);
|
|
$lackItem = null;
|
|
if (!$this->_hasEnoughItems($costItems, $lackItem)) {
|
|
$this->_rspErr(2, $this->_getLackItemErrMsg($lackItem));
|
|
return;
|
|
}
|
|
}
|
|
|
|
$itemStore = mt\ShopChest::getRandomItemListByChestType($meta['sub_type']);
|
|
$result = array();
|
|
for ($i = 0; $i < $num; $i++) {
|
|
$record = array();
|
|
foreach ($itemStore as $key => $value) {
|
|
$item = $this->weighted_random($value);
|
|
$itemMeta = mt\Item::get($item['item_id']);
|
|
if (!$itemMeta) {
|
|
$this->_rspErr(2, 'item_id is invalid ' . $item['item_id'] . ' in blind box ' . $shop['goods_id']);
|
|
return;
|
|
}
|
|
$propertyChgService = new services\PropertyChgService();
|
|
if ($item['item_type'] == 2) {
|
|
$this->internalAddItem($propertyChgService, $itemMeta, $item['num'], 1);
|
|
} else {
|
|
for ($j = 0; $j < $item['num']; $j++) {
|
|
$this->internalAddItem($propertyChgService, $itemMeta, 1, 1);
|
|
}
|
|
}
|
|
$record[$key] = array("item_id" => $item['item_id'], "item_num" => $item['num']);
|
|
array_push($result, $record[$key]);
|
|
}
|
|
if ($isFreeBuy) {
|
|
$this->addFreeBuyRecord($shop);
|
|
}
|
|
}
|
|
|
|
error_log("buyBlindBox start " . json_encode(
|
|
array(
|
|
'account' => $account,
|
|
'id' => $id,
|
|
'num' => $num,
|
|
'cost' => $cost,
|
|
'freeBuy' => $isFreeBuy,
|
|
'itemListStore' => $result,
|
|
)
|
|
));
|
|
|
|
if (!$isFreeBuy) {
|
|
$this->_decItems($costItems);
|
|
$event = [
|
|
'name' => LogService::SHOP_BUY_ITEM_BLIND_BOX,
|
|
'val' => $costItems[0]['item_num']
|
|
];
|
|
LogService::consumeDiamond($event);
|
|
}
|
|
|
|
$this->_rspData(
|
|
array(
|
|
'reuslt' => $result,
|
|
)
|
|
);
|
|
}
|
|
|
|
private function buyGoods()
|
|
{
|
|
$shopId = getReqVal('shop_id', 0);
|
|
$goodsId = getReqVal('goods_id', 0);
|
|
$itemNum = getReqVal('goods_num', 0);
|
|
$costItemId = getReqVal('cost_item_id', 0);
|
|
$itemId = $goodsId;
|
|
|
|
if ($shopId == mt\Shop::OUTSIDE_SHOP) {
|
|
$this->outsideBuy($shopId, $itemId, $itemNum, $costItemId);
|
|
return;
|
|
}
|
|
|
|
$propertyChgService = new services\PropertyChgService();
|
|
$itemMeta = mt\Item::get($itemId);
|
|
if (!$itemMeta) {
|
|
$this->_rspErr(1, 'goods_id parameter error');
|
|
return;
|
|
}
|
|
$goodsMeta = mt\ShopGoods::getGoodsInfo($shopId, $goodsId);
|
|
if (!$goodsMeta) {
|
|
$this->_rspErr(1, 'goods_id parameter error');
|
|
return;
|
|
}
|
|
$buyRecordHash = ShopBuyRecord::allToHash();
|
|
$boughtTimes = 1;
|
|
switch ($itemMeta['limit_type']) {
|
|
case mt\Item::DAILY_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $itemMeta['id']);
|
|
$boughtTimes = $buyRecord ? $buyRecord['this_day_buy_times'] + 1 : 1;
|
|
if ($buyRecord && getXVal($buyRecord, 'this_day_buy_times', 0) >= $itemMeta['limit_num']) {
|
|
$this->_rspErr(2, 'Has reached the maximum number of purchase restrictions today');
|
|
return;
|
|
}
|
|
if ($itemMeta['limit_num'] <= 0) {
|
|
$this->_rspErr(2, 'The maximum number of purchase restrictions has been reached');
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case mt\Item::WEEKLY_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $itemMeta['id']);
|
|
$boughtTimes = $buyRecord ? $buyRecord['this_week_buy_times'] + 1 : 1;
|
|
if ($buyRecord && getXVal($buyRecord, 'this_week_buy_times', 0) >= $itemMeta['limit_num']) {
|
|
$this->_rspErr(2, 'The maximum number of purchase restrictions this week has been reached');
|
|
return;
|
|
}
|
|
if ($itemMeta['limit_num'] <= 0) {
|
|
$this->_rspErr(2, 'The maximum number of purchase restrictions has been reached');
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case mt\Item::TOTAL_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $itemMeta['id']);
|
|
$boughtTimes = $buyRecord ? $buyRecord['total_buy_times'] + 1 : 1;
|
|
if ($buyRecord && getXVal($buyRecord, 'total_buy_times', 0) >= $itemMeta['limit_num']) {
|
|
$this->_rspErr(2, 'The maximum number of purchase restrictions has been reached');
|
|
return;
|
|
}
|
|
if ($itemMeta['limit_num'] <= 0) {
|
|
$this->_rspErr(2, 'he maximum number of purchase restrictions has been reached');
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
default: {
|
|
}
|
|
break;
|
|
} {
|
|
$errCode = 0;
|
|
$errMsg = '';
|
|
if (!$this->canBuy($itemMeta, $errCode, $errMsg)) {
|
|
$this->_rspErr($errCode, $errMsg);
|
|
return;
|
|
}
|
|
}
|
|
$priceInfo = mt\Item::getPriceInfo($itemMeta);
|
|
if (empty($priceInfo)) {
|
|
$this->_rspErr(2, 'config error');
|
|
return;
|
|
}
|
|
$costItems = $this->getCostItems($priceInfo, $costItemId);
|
|
if (empty($costItems)) {
|
|
$this->_rspErr(2, 'config error2');
|
|
return;
|
|
}
|
|
$lackItem = null;
|
|
if (!$this->_hasEnoughItems($costItems, $lackItem)) {
|
|
$this->_rspErr(3, $this->_getLackItemErrMsg($lackItem));
|
|
return;
|
|
}
|
|
$this->_decItems($costItems);
|
|
$this->internalAddItem($propertyChgService, $itemMeta, 1, 0);
|
|
$awardService = new services\AwardService();
|
|
$awardService->addItem($itemId, $itemNum);
|
|
ShopBuyRecord::add($itemId, $itemNum);
|
|
$goodsDto = array(
|
|
'goods_id' => $itemMeta['id'],
|
|
'item_id' => $itemMeta['id'],
|
|
'price_info' => array(
|
|
'item_id' => $itemMeta['id'],
|
|
'cost_list' => array(),
|
|
'discount_begin_time' => phpcommon\datetimeToTimestamp($itemMeta['discount_begin']),
|
|
'discount_end_time' => phpcommon\datetimeToTimestamp($itemMeta['discount_end'])
|
|
),
|
|
'flag_icon' => $goodsMeta['tag'],
|
|
'limit_type' => $itemMeta['limit_type'],
|
|
'bought_times' => $boughtTimes,
|
|
'total_buy_times' => $itemMeta['limit_num'],
|
|
); {
|
|
$priceInfo = mt\Item::getPriceInfo($itemMeta);
|
|
if (!empty($priceInfo)) {
|
|
$goodsDto['price_info'] = $priceInfo['price_info'];
|
|
}
|
|
}
|
|
$propertyChgService->addUserChg();
|
|
$this->_rspData(
|
|
array(
|
|
'award' => $awardService->toDto(),
|
|
'property_chg' => $propertyChgService->toDto(),
|
|
'goods_chg' => $goodsDto
|
|
)
|
|
);
|
|
}
|
|
|
|
private function getDiscountList()
|
|
{
|
|
$items = array(); {
|
|
$types = array(
|
|
mt\Item::HERO_TYPE,
|
|
mt\Item::HERO_SKIN_TYPE,
|
|
mt\Item::GUN_SKIN_TYPE
|
|
);
|
|
mt\Item::filter(function ($meta) use (&$items, &$types) {
|
|
if (mt\Item::inTypes($meta, $types)) {
|
|
array_push($items, $meta);
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
$goodsDtoList = array();
|
|
array_walk($items, function ($val) use (&$priceList, &$goodsDtoList) {
|
|
$goodsDto = array(
|
|
'item_id' => $val['id'],
|
|
'gold_discount' => 0,
|
|
'diamond_discount' => 0,
|
|
);
|
|
$priceInfo = mt\Item::getPriceInfo($val);
|
|
if (!empty($priceInfo)) {
|
|
foreach ($priceInfo['price_info']['cost_list'] as $costGroup) {
|
|
foreach ($costGroup as $cost) {
|
|
if ($cost['discount'] > 0) {
|
|
switch ($cost['item_id']) {
|
|
case V_ITEM_GOLD: {
|
|
$goodsDto['gold_discount'] = $cost['discount'];
|
|
}
|
|
break;
|
|
case V_ITEM_DIAMOND: {
|
|
$goodsDto['diamond_discount'] = $cost['discount'];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ($goodsDto['gold_discount'] > 0 || $goodsDto['diamond_discount'] > 0) {
|
|
array_push($goodsDtoList, $goodsDto);
|
|
}
|
|
}
|
|
});
|
|
$this->_rspData(
|
|
array(
|
|
'goods_list' => $goodsDtoList,
|
|
)
|
|
);
|
|
}
|
|
|
|
private function info()
|
|
{
|
|
$shopId = getReqVal('shop_id', 0);
|
|
if ($shopId == mt\Shop::OUTSIDE_SHOP) {
|
|
$this->getOutsideShopInfo();
|
|
return;
|
|
}
|
|
$goodsList = mt\ShopGoods::getGoodsList($shopId);
|
|
if (!$goodsList) {
|
|
$this->_rspData(
|
|
array(
|
|
'info' => array(
|
|
'shop_id' => $shopId,
|
|
'goods_list1' => array(),
|
|
'goods_list2' => array(),
|
|
)
|
|
)
|
|
);
|
|
return;
|
|
}
|
|
$buyRecordHash = ShopBuyRecord::allToHash();
|
|
$goodsDtoList1 = array();
|
|
$goodsDtoList2 = array();
|
|
foreach ($goodsList as $goods) {
|
|
$itemMeta = mt\Item::get($goods['goods_id']);
|
|
if ($itemMeta) {
|
|
$goodsDto = array(
|
|
'goods_id' => $goods['goods_id'],
|
|
'item_id' => $itemMeta['id'],
|
|
'price_info' => null,
|
|
'flag_icon' => $goods['tag'],
|
|
'limit_type' => $itemMeta['limit_type'],
|
|
'bought_times' => 0,
|
|
'total_buy_times' => $itemMeta['limit_num'],
|
|
);
|
|
switch ($itemMeta['limit_type']) {
|
|
case mt\Item::DAILY_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $itemMeta['id']);
|
|
$goodsDto['bought_times'] = $buyRecord ? $buyRecord['this_day_buy_times'] : 0;
|
|
}
|
|
break;
|
|
case mt\Item::WEEKLY_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $itemMeta['id']);
|
|
$goodsDto['bought_times'] = $buyRecord ? $buyRecord['this_week_buy_times'] : 0;
|
|
}
|
|
break;
|
|
case mt\Item::TOTAL_BUY_LIMIT: {
|
|
$buyRecord = getXVal($buyRecordHash, $itemMeta['id']);
|
|
$goodsDto['bought_times'] = $buyRecord ? $buyRecord['total_buy_times'] : 0;
|
|
}
|
|
break;
|
|
default: {
|
|
}
|
|
break;
|
|
}
|
|
$priceInfo = mt\Item::getPriceInfo($itemMeta);
|
|
if (!empty($priceInfo)) {
|
|
$goodsDto['price_info'] = $priceInfo['price_info'];
|
|
array_push($goodsDtoList1, $goodsDto);
|
|
}
|
|
}
|
|
}
|
|
$this->_rspData(
|
|
array(
|
|
'info' => array(
|
|
'shop_id' => $shopId,
|
|
'goods_list1' => $goodsDtoList1,
|
|
'goods_list2' => $goodsDtoList2,
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|