diff --git a/doc/Shop.py b/doc/Shop.py index 63d667ba..62041fd8 100644 --- a/doc/Shop.py +++ b/doc/Shop.py @@ -85,20 +85,6 @@ class Shop(object): ['status', 0, '订单状态 0:未支付 1:已支付 2:支付失败'], ] }, - { - 'name': 'getPayMethods', - 'desc': '获取支付方式', - 'group': 'Shop', - 'url': 'webapp/index.php?c=Shop&a=getPayMethods', - 'params': [ - _common.ReqHead(), - ['token_type', 0, "选用币种"], - ], - 'response': [ - _common.RspHead(), - ['!pay_methods', [_common.PayMethod()], '支付方式列表'], - ] - }, { 'name': 'boxPreview', 'desc': '宝箱道具预览', diff --git a/sql/gamedb.sql b/sql/gamedb.sql index 6dbdf24f..d1dfafc6 100644 --- a/sql/gamedb.sql +++ b/sql/gamedb.sql @@ -1278,6 +1278,64 @@ CREATE TABLE `t_user_honor` ( ) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `t_inapp_order` +-- + +DROP TABLE IF EXISTS `t_inapp_order`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_inapp_order` ( + `idx` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id', + `order_id` varchar(60) NOT NULL DEFAULT '' COMMENT '订单id', + `sp_order_id` varchar(64) DEFAULT NULL COMMENT 'app store order_id', + `platform` int(11) NOT NULL DEFAULT '0' COMMENT '0: ios 1: android', + `account_id` varchar(60) NOT NULL DEFAULT '' COMMENT '申请账号id', + `address` varchar(60) DEFAULT NULL COMMENT '申请时账号绑定的钱包', + `item_id` int(11) NOT NULL DEFAULT '0' COMMENT '物品id', + `item_num` bigint(20) NOT NULL DEFAULT '0' COMMENT '物品数量', + `price` bigint(20) NOT NULL DEFAULT '0' COMMENT '价格', + `status` int(11) NOT NULL DEFAULT '0' COMMENT 'status', + `createtime` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间', + `modifytime` int(11) NOT NULL DEFAULT '0' COMMENT '修改时间', + PRIMARY KEY (`idx`), + UNIQUE KEY `order_id` (`order_id`), + UNIQUE KEY `platform_sp_order_id` (`platform_sp_order_id`), + KEY `account_id` (`account_id`), + KEY `address` (`address`), + KEY `sp_order_id` (`sp_order_id`) +) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `t_outapp_order` +-- + +DROP TABLE IF EXISTS `t_outapp_order`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `t_outapp_order` ( + `idx` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id', + `order_id` varchar(60) NOT NULL DEFAULT '' COMMENT '订单id', + `sp_order_id` varchar(64) DEFAULT NULL COMMENT 'app store order_id', + `platform` int(11) NOT NULL DEFAULT '0' COMMENT '0: ios 1: android', + `account_id` varchar(60) NOT NULL DEFAULT '' COMMENT '申请账号id', + `address` varchar(60) DEFAULT NULL COMMENT '申请时账号绑定的钱包', + `item_id` int(11) NOT NULL DEFAULT '0' COMMENT '物品id', + `item_num` bigint(20) NOT NULL DEFAULT '0' COMMENT '物品数量', + `price` bigint(20) NOT NULL DEFAULT '0' COMMENT '价格', + `status` int(11) NOT NULL DEFAULT '0' COMMENT 'status', + `createtime` int(11) NOT NULL DEFAULT '0' COMMENT '创建时间', + `modifytime` int(11) NOT NULL DEFAULT '0' COMMENT '修改时间', + PRIMARY KEY (`idx`), + UNIQUE KEY `order_id` (`order_id`), + UNIQUE KEY `platform_sp_order_id` (`platform_sp_order_id`), + KEY `account_id` (`account_id`), + KEY `address` (`address`), + KEY `sp_order_id` (`sp_order_id`) +) ENGINE=InnoDB AUTO_INCREMENT=10001 DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +/*!40101 SET character_set_client = @saved_cs_client */; + DROP TABLE IF EXISTS `t_web2_order`; CREATE TABLE `t_web2_order` ( `idx` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id', diff --git a/webapp/controller/BlockChainController.class.php b/webapp/controller/BlockChainController.class.php index 8f8c5534..916ddcda 100644 --- a/webapp/controller/BlockChainController.class.php +++ b/webapp/controller/BlockChainController.class.php @@ -281,6 +281,53 @@ class BlockChainController extends BaseAuthedController { } } + public function buyDiamond() + { + $num = getReqVal('num', 0); + if (!is_numeric($num)) { + $this->_rspErr(1, "num is invalid, {$num}"); + return; + } + if ($num <= 0) { + $this->_rspErr(1, "num is invalid, {$num}"); + return; + } + + $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 + ) + ); + } + private static function getWeb3ServiceUrl() { if (SERVER_ENV == _TEST) { diff --git a/webapp/controller/CallbackController.class.php b/webapp/controller/CallbackController.class.php index 6266d6c5..25769447 100644 --- a/webapp/controller/CallbackController.class.php +++ b/webapp/controller/CallbackController.class.php @@ -5,37 +5,17 @@ 需要对web3service回调的做签名校验!!! */ -class CallbackController extends BaseController { +require_once('services/CallBack.php'); - private $handlers = array( - 'mintNftHero' => 'MintNftHero' , - 'gameItemMallBuyOk' => 'GameItemMallBuyOk', - 'gameItemMarketBuyOk' => 'GameItemMarketBuyOk', - 'MarketSellOrderOk' => 'MarketSellOrderOk', - 'MarketBuyOrderOk' => 'MarketBuyOrderOk', - 'MarketCancelOrderOk' => 'MarketCancelOrderOk', - 'MarketPriceUpdateOrderOk' => 'MarketPriceUpdateOrderOk', - 'ShopBuyGoodsDirect' => 'ShopBuyGoodsDirect', - //'ShopInappPurchaseDiamonds' => 'ShopInappPurchaseDiamonds', - ); +use services\CallBackService; + +class CallbackController extends BaseController { public function dispatch() { - error_log("CallbackController Begin"); + $cbService = new CallBackService(); $action = getReqVal('action', ''); - if (key_exists($action, $this->handlers)) { - error_log("Callback:dispatch____". json_encode($_REQUEST)); - $this->internalDispatch($this->handlers[$action]); - } else { - $this->_rspErr(500, 'not found'); - } - } - - private function internalDispatch($className) - { - require_once ('services/callback/' . $className . '.php'); - $obj = eval("return new services\\" . $className . "();"); - $obj->process(); + $cbService->dispatch($action); } } diff --git a/webapp/controller/ShopController.class.php b/webapp/controller/ShopController.class.php index 396fa340..ac88fe74 100644 --- a/webapp/controller/ShopController.class.php +++ b/webapp/controller/ShopController.class.php @@ -2,89 +2,46 @@ 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/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('models/InAppOrder.php'); +require_once('models/OutAppOrder.php'); require_once('services/AwardService.php'); require_once('services/PropertyChgService.php'); -require_once('services/BlockChainService.php'); - -require_once('phpcommon/bignumber.php'); - +require_once('services/ShopService.php'); require_once('services/LogService.php'); -require_once('services/callback/ShopAddItemService.php'); +require_once('services/CallBack.php'); -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\Dailyselection; use mt\ShopChest; use mt\ShopGoods; -use models\Transaction; -use models\BcOrder; + +use models\Hero; +use models\ShopBuyRecord; +use models\InAppOrder; +use models\OutAppOrder; + use services\LogService; -use services\ShopAddItemService; +use services\ShopService; +use services\CallBackService; -class ShopController extends BaseAuthedController -{ +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() + { + $a = getReqVal('a', ''); + if ( + $a != 'buyGoodsDirect' && + $a != 'inappPurchaseDiamonds' + ) { + parent::_handlePre(); + } + } public function getGoodsList() { @@ -95,79 +52,140 @@ class ShopController extends BaseAuthedController } else { $goodsMetaList = mt\ShopGoods::getGoodsList($shopId); } - - $goodsMetaList = $goodsMetaList ? $goodsMetaList : array(); - $buyRecordHash = ShopBuyRecord::allToHash(); - - $goodsList = array(); - foreach ($goodsMetaList as $goodsMeta) { - $goodsDto = array( - 'goods_meta' => $this->goodsMetaToInfo($goodsMeta), - 'bought_times' => 0, - 'free_num' => 0, - ); - array_push($goodsList, $goodsDto); - switch ($goodsMeta['limit_type']) { - case mt\Item::DAILY_BUY_LIMIT: { - $buyRecord = getXVal($buyRecordHash, $goodsMeta['id']); - $goodsDto['bought_times'] = $buyRecord ? $buyRecord['this_day_buy_times'] : 0; - } - break; - case mt\Item::WEEKLY_BUY_LIMIT: { - $buyRecord = getXVal($buyRecordHash, $goodsMeta['id']); - $goodsDto['bought_times'] = $buyRecord ? $buyRecord['this_week_buy_times'] : 0; - } - break; - case mt\Item::TOTAL_BUY_LIMIT: { - $buyRecord = getXVal($buyRecordHash, $goodsMeta['id']); - $goodsDto['bought_times'] = $buyRecord ? $buyRecord['total_buy_times'] : 0; - } - break; - default: { - } - break; - } - - $goodsId = $goodsMeta['goods_id']; - $itemMeta = mt\Item::get($goodsId); - if ($itemMeta) { - // 如果是皮肤,判断是否已经拥有,如果已经拥有,不能购买 - if ($itemMeta['type'] == mt\Item::HERO_SKIN_TYPE) { - $errCode = 0; - $errMsg = ''; - if (!$this->canBuy($itemMeta, $errCode, $errMsg)) { - $goods['bought_times'] = 1; - } else { - $goods['bought_times'] = 0; - } - } - } else { - // error !!!!!! - error_log('item not found:' . $goodsId); - } - - if (!empty($goods['free_type'])) { - $count = $this->countFreeBuyTimes($goodsMeta['free_type'], - $goodsMeta['id'], - $goodsMeta['goods_id']); - $goods['free_num'] = $goods['free_num'] - $count; - } - } - - $this->_rspData( + $goodsList = ShopService::getGoodsList($shopId); + myself()->_rspData( array( 'goods_list' => $goodsList, ) ); } - public function startGoodsDirect() + public function buyGoods() + { + $goodsUuid = getReqVal('goods_uuid', 0); + $tokenType = getReqVal('token_type', ''); + $goodsNum = getReqVal('goods_num', 0); + + if ($goodsNum < 1) { + myself()->_rspErr(1, "goods_num parameter error, goods_num: {$goodsNum}"); + return; + } + + $goodsMeta = mt\ShopGoods::getByGoodsUuid($goodsUuid); + if (!$goodsMeta) { + myself()->_rspErr(1, 'goods not found'); + return; + } + if ($goodsNum > $goodsMeta['max_amount']) { + myself()->_rspErr(1, "goods_num parameter error, max_amount: {$goodsMeta['max_amount']}"); + return; + } + $itemMeta = mt\Item::get($goodsMeta['item_id']); + if (!$itemMeta) { + myself()->_rspErr(1, 'goods not found, goods_id: ' . $goodsMeta['goods_id']); + return; + } + $errCode = 0; + $errMsg = ''; + if ($itemMeta['type'] == mt\Item::HERO_SKIN_TYPE) { + if (!$this->canBuy($itemMeta, $errCode, $errMsg)) { + myself()->_rspErr($errCode, $errMsg); + return; + } + } + if (!ShopService::buyLimitCheck($goodsMeta, $errCode, $errMsg)) { + myself()->_rspErr($errCode, $errMsg); + return; + } + + $desiredTokenType = $goodsMeta['token_type']; + $checkTokenType = splitStr1($desiredTokenType); + $tokenPos = array_search($tokenType, $checkTokenType, true); + $isFreeBuy = false; + if (!empty($goodsMeta['free_type'])) { + $count = $this->countFreeBuyTimes($goodsMeta['free_type'], $goodsMeta['id'], $goodsMeta['item_id']); + if ($count < $goodsMeta['free_num']) { + $isFreeBuy = true; + } + } + $propertyChgService = new services\PropertyChgService(); + $awardService = new services\AwardService(); + if ($isFreeBuy) { + $awardService->addItem($itemMeta['id'], $goodsNum); + myself()->_rspData( + array( + 'award' => $awardService->toDto(), + 'property_chg' => $propertyChgService->toDto(), + //'goods_chg' => $goodsDto + ) + ); + return; + } else { + if (!in_array($tokenType, $checkTokenType)) { + myself()->_rspErr(1, "token_type parameter error, desired_token_type: {$desiredTokenType}"); + return; + } + } + + $priceArray = splitStr1($goodsMeta['price']); + $discountArray = splitStr1($goodsMeta['discount']); + + $needPrice = $priceArray[$tokenPos]; + $discount = $discountArray[$tokenPos]; + + $discountBegin = strtotime($goodsMeta['discount_begin']); + $discountEnd = strtotime($goodsMeta['discount_end']); + $nowTime = myself()->_getNowTime(); + + if ($nowTime >= $discountBegin && $nowTime < $discountEnd) { + $needPrice = ceil($needPrice * ($discount / 100.0)); + } + + $costItemId = myself()->getCostItemIdByTokenType($tokenType); + $costItems = array( + 'item_id' => $costItemId, + 'item_num' => $goodsNum * $needPrice + ); + if (!in_array( + $tokenType, + array( + mt\Shop::TOKEN_TYPE_GOLD, + mt\Shop::TOKEN_TYPE_DIAMOND + ) + )) { + myself()->_rspErr(1, "token_type is unsupport, {$tokenType}"); + return; + } + $lackItem = null; + if (!myself()->_hasEnoughItems($costItems, $lackItem)) { + myself()->_rspErr(2, myself()->_getLackItemErrMsg($lackItem)); + return; + } + ShopBuyRecord::add($itemMeta['id'], $goodsNum); + myself()->_decItems($costItems); + for ($i = 0; $i < $goodsNum; $i++) { + $this->internalAddItem($awardService, + $propertyChgService, + $itemMeta, + $goodsMeta['goods_num'] + ); + } + $propertyChgService->addUserChg(); + $this->_rspData( + array( + 'award' => $awardService->toDto(), + 'property_chg' => $propertyChgService->toDto(), + ) + ); + } + + public function outappPurchase() { $id = getReqVal('id', 0); - $token_type = getReqVal('token_type', ''); - $goods_num = getReqVal('goods_num', 1); + $tokenType = getReqVal('token_type', ''); + $goodsNum = getReqVal('goods_num', 1); - if ($goods_num <= 0) { + if ($goodsNum <= 0) { $this->_rspErr(1, 'goods_num is invalid'); return; } @@ -178,7 +196,7 @@ class ShopController extends BaseAuthedController return; } - if ($goods['shop_id'] == 9 && $goods_num > 1) { + if ($goods['shop_id'] == 9 && $goodsNum > 1) { $this->_rspErr(1, 'goods_num is invalid'); return; } @@ -199,7 +217,7 @@ class ShopController extends BaseAuthedController 'createtime' => myself()->_getNowTime(), 'id' => $id, 'item_id' => $goods['goods_id'] ? $goods['goods_id'] : 0, - 'goods_num' => $goods_num, + 'goods_num' => $goodsNum, 'status' => 0, // 0-客户端申请了订单 1-订单完成 2-订单失败 ) ); @@ -222,67 +240,26 @@ class ShopController extends BaseAuthedController ) ); } else { - $this->_rspErr(1, "insert error, id: {$id}, token_type: {$token_type}, goods_num: {$goods_num}"); + $this->_rspErr(1, "insert error, id: {$id}, token_type: {$tokenType}, goods_num: {$goodsNum}"); } } - public function statusGoodsDirect() + public function inappPurchase() { - $order_id = getReqVal('order_id', ''); - - $conn = myself()->_getMysql(''); - - $row = SqlHelper::selectOne( - $conn, - 't_shop_buy_order', - array('status', 'id'), - array( - 'order_id' => $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}"); - } - } - - public function startInappPurchase() - { - $self = myself(); - if (!$self) { - $this->_rspErr(1, "start purchase failed"); - return; - } - - $id = getReqVal('id', 0); - $goods = mt\ShopGoods::get($id); + $goodsUuid = getReqVal('goods_uuid', 0); + $goodsNum = getReqVal('goods_num', 0); + $goods = mt\ShopGoods::getByGoodsUuid($goodsUuid); if (!$goods) { $this->_rspErr(2, "start purchase failed"); return; } - if ($goods['shop_id'] != 9) { + if ($goods['shop_id'] != mt\Shop::INAPP_SHOP) { $this->_rspErr(3, "start purchase failed"); return; } - $goods_num = getReqVal('goods_num', 1); - - $account_id = $self->_getAccountId(); - $address = $self->_getAddress(); - if (empty($address)) { - $this->_rspErr(4, "start purchase failed"); - return; - } - $item_id = $goods['goods_id']; - $item_num = $goods['goods_num'] * $goods_num; + $item_num = $goods['goods_num'] * $goodsNum; $conn = $self->_getMysql(''); @@ -294,7 +271,7 @@ class ShopController extends BaseAuthedController 'item_id' => $item_id, 'item_num' => $item_num, 'id' => $id, - 'goods_num' => $goods_num, + 'goods_num' => $goodsNum, 'price' => $goods['price'], )); @@ -315,370 +292,30 @@ class ShopController extends BaseAuthedController )); } - private function genOrderId($id) + public function queryInappPurchase() { - $order_id_base = date('YmdHis') . "10000000"; - $divIdx = phpcommon\bnToStr(gmp_mod($id, 9999999)); - $order_id = phpcommon\bnAdd_s($order_id_base, $divIdx); - return $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"); + $orderId = getReqVal('order_id', ''); + $orderDb = InAppOrder::find($orderId); + if ($orderDb) { + myself()->_rspErr(1, 'order not found'); return; } - $this->_rspData($order); - } - - public function buyGoods() - { - $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; - - $itemMeta = mt\Item::get($row['goods_id']); - if (!$itemMeta) { - $this->_rspErr(1, 'goods not found, goods_id: ' . $row['goods_id']); - return; - } - - if ($itemMeta['type'] == mt\Item::HERO_SKIN_TYPE) { - $errCode = 0; - $errMsg = ''; - if (!$this->canBuy($itemMeta, $errCode, $errMsg)) { - $this->_rspErr($errCode, $errMsg); - return; - } - } else { - - 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); - if (!is_numeric($num)) { - $this->_rspErr(1, "num is invalid, {$num}"); - return; - } - if ($num <= 0) { - $this->_rspErr(1, "num is invalid, {$num}"); - return; - } - - $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, - )), + $this->_rspData(array( + 'order_id' => $orderDb['order_id'], + 'item_id' => $orderDb['item_id'], + 'item_num' => $orderDb['item_num'], + 'status' => $orderDb['status'], )); - - $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 boxPreview() { $id = getReqVal('id', 0); $goods = mt\ShopGoods::get($id); - $goods_id = $goods['goods_id']; - $shop_id = $goods['shop_id']; + $goodsId = $goods['goods_id']; + $shopId = $goods['shop_id']; - $meta = mt\Item::get($goods_id); + $meta = mt\Item::get($goodsId); if ($meta['type'] != mt\Item::CHEST_BOX_TYPE) { $this->_rspErr(2, 'goods_id is invalid'); return; @@ -711,14 +348,13 @@ class ShopController extends BaseAuthedController array( 'items' => array_keys($record), 'free_num' => $free_num, - 'pending' => 0, ) ); } - private function getCostItemIdByTokenType($token_type) + private function getCostItemIdByTokenType($tokenType) { - switch ($token_type) { + switch ($tokenType) { case ShopController::TOKEN_TYPE_GOLD: return V_ITEM_GOLD; break; @@ -739,216 +375,71 @@ class ShopController extends BaseAuthedController } } - private function makeCostItems($item_id, $num) - { - $costItems = array( - array( - 'item_id' => $item_id, - 'item_num' => $num - ) - ); - return $costItems; - } - - private function internalAddItem($propertyChgService, $itemMeta, $count, $sysAdd, $grade = null) + private function internalAddItem($awardService, + $propertyChgService, + $itemMeta, + $count + ) { switch ($itemMeta['type']) { - case mt\Item::HERO_TYPE: { - if (empty($grade)) { - $grade = 0; - } - switch ($grade) { - case 1: { - Hero::addHero1($itemMeta); - } - break; - case 2: { - Hero::addHero2($itemMeta); - } - break; - case 3: { - Hero::addHero3($itemMeta); - } - break; - default: { - Hero::addHero($itemMeta); - } - break; - } - $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(); - } else { - Bag::addItem($itemMeta['id'], $count); - $propertyChgService->addBagChg(); - } - } - break; + case mt\Item::HERO_TYPE: + { + if (empty($grade)) { + $grade = 0; + } + switch ($grade) { + case 1: + { + Hero::addHero1($itemMeta); + } + break; + case 2: + { + Hero::addHero2($itemMeta); + } + break; + case 3: + { + Hero::addHero3($itemMeta); + } + break; + default: + { + Hero::addHero($itemMeta); + } + break; + } + $propertyChgService->addHeroChg(); + $propertyChgService->addUserChg(); + } + break; + default: + { + myself()->_addItems( + array( + 'item_id' => $itemMeta['id'], + 'item_num' => $count + ), + $awardService, + $propertyChgService); + } + break; } } - private function canBuy($itemMeta, &$errCode, &$errMsg) + public function buyGoodsDirect() { + error_log('buyGoodsDirect:' . json_encode($_REQUEST)); + $cbService = new CallBackService(); + $action = 'inappPurchase'; + $cbService->dispatch($action); + } + + public function inappPurchaseDiamonds() { - $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($address = null) - { - if (!$address) { - $address = myself()->_getAddress(); - } - $conn = myself()->_getMysql(''); - - $exist = SqlHelper::selectOne( - $conn, - 't_first_topup', - array('address'), - array('address' => $address) - ); - if ($exist) { - return; - } - - // 开始首充奖励活动进程 - $chk = SqlHelper::insert( - $conn, - 't_first_topup', - array( - 'address' => $address, - '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) - { - return 0; - switch ($free_type) { - case 1: { - $dayTime = myself()->_getNowDaySeconds(); - $sql = 'SELECT COUNT(idx) 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 goodsMetaToInfo($goodsMeta) { - return array( - - ); + error_log('inappPurchaseDiamonds:' . json_encode($_REQUEST)); + $cbService = new CallBackService(); + $action = 'outappPurchase'; + $cbService->dispatch($action); } } diff --git a/webapp/models/InAppOrder.php b/webapp/models/InAppOrder.php new file mode 100644 index 00000000..6ed6b0ba --- /dev/null +++ b/webapp/models/InAppOrder.php @@ -0,0 +1,25 @@ +_get(), + 't_inapp_order', + array( + 'order_id' => $orderId, + ) + ); + return $row; + } + +} diff --git a/webapp/models/OutAppOrder.php b/webapp/models/OutAppOrder.php new file mode 100644 index 00000000..6f632737 --- /dev/null +++ b/webapp/models/OutAppOrder.php @@ -0,0 +1,54 @@ +_get(), + 't_outapp_order', + array( + 'order_id' => $orderId, + ) + ); + return $row; + } + + public static function markFinished($orderId) + { + SqlHelper::update( + myself()->_get(), + 't_outapp_order', + array( + 'order_id' => $orderId, + ), + array( + 'state' => self::FINISHED_STATE, + ) + ); + } + + public static function markFailed($orderId) + { + SqlHelper::update( + myself()->_get(), + 't_outapp_order', + array( + 'order_id' => $orderId, + ), + array( + 'state' => self::FAILED_STATE, + ) + ); + } + +} diff --git a/webapp/models/ShopBuyRecord.php b/webapp/models/ShopBuyRecord.php index ce8e9598..9a64a820 100644 --- a/webapp/models/ShopBuyRecord.php +++ b/webapp/models/ShopBuyRecord.php @@ -149,4 +149,5 @@ class ShopBuyRecord extends BaseModel return $row['account_id']; } + } diff --git a/webapp/mt/Shop.php b/webapp/mt/Shop.php index 93357b97..b03bcc31 100644 --- a/webapp/mt/Shop.php +++ b/webapp/mt/Shop.php @@ -6,6 +6,44 @@ use phpcommon; class Shop { + 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; + + const INAPP_SHOP = 9; const OUTSIDE_SHOP = 100; public static function get($id) @@ -21,7 +59,7 @@ class Shop { array_push(self::$shopNameList, $meta); } } - + return self::$shopNameList; } @@ -32,7 +70,7 @@ class Shop { } return self::$metaList; } - + protected static $shopNameList; protected static $metaList; diff --git a/webapp/mt/ShopGoods.php b/webapp/mt/ShopGoods.php index dd9ef143..010dca95 100644 --- a/webapp/mt/ShopGoods.php +++ b/webapp/mt/ShopGoods.php @@ -12,6 +12,11 @@ class ShopGoods return getXVal(self::getMetaList(), $id); } + public static function getByGoodsUuid($goodsUuid) + { + return getXVal(self::getMetaList(), $goodsUuid); + } + public static function getGoodsList($shopId) { self::mustBeShopGoodsHash(); diff --git a/webapp/services/CallBack.php b/webapp/services/CallBack.php new file mode 100644 index 00000000..f0d2bd98 --- /dev/null +++ b/webapp/services/CallBack.php @@ -0,0 +1,39 @@ + 'MintNftHero' , + 'gameItemMallBuyOk' => 'GameItemMallBuyOk', + 'gameItemMarketBuyOk' => 'GameItemMarketBuyOk', + 'MarketSellOrderOk' => 'MarketSellOrderOk', + 'MarketBuyOrderOk' => 'MarketBuyOrderOk', + 'MarketCancelOrderOk' => 'MarketCancelOrderOk', + 'MarketPriceUpdateOrderOk' => 'MarketPriceUpdateOrderOk', + 'inappPurchase' => 'InAppPurchase', + 'outappPurchase' => 'OutAppPurchase', + ); + + public function dispatch($action) + { + error_log("CallbackController Begin"); + if (key_exists($action, $this->handlers)) { + error_log("Callback:dispatch____". json_encode($_REQUEST)); + $this->internalDispatch($this->handlers[$action]); + } else { + myself()->_rspErr(500, 'not found'); + die(); + } + } + + private function internalDispatch($className) + { + require_once ('services/callback/' . $className . '.php'); + $obj = eval("return new services\\" . $className . "();"); + $obj->process(); + die(); + } + +} diff --git a/webapp/services/ShopService.php b/webapp/services/ShopService.php new file mode 100644 index 00000000..4655667f --- /dev/null +++ b/webapp/services/ShopService.php @@ -0,0 +1,195 @@ + self::goodsMetaToInfo($goodsMeta), + 'bought_times' => 0, + 'free_num' => 0, + ); + array_push($goodsList, $goodsDto); + switch ($goodsMeta['limit_type']) { + case mt\Item::DAILY_BUY_LIMIT: { + $buyRecord = getXVal($buyRecordHash, $goodsMeta['id']); + $goodsDto['bought_times'] = $buyRecord ? $buyRecord['this_day_buy_times'] : 0; + } + break; + case mt\Item::WEEKLY_BUY_LIMIT: { + $buyRecord = getXVal($buyRecordHash, $goodsMeta['id']); + $goodsDto['bought_times'] = $buyRecord ? $buyRecord['this_week_buy_times'] : 0; + } + break; + case mt\Item::TOTAL_BUY_LIMIT: { + $buyRecord = getXVal($buyRecordHash, $goodsMeta['id']); + $goodsDto['bought_times'] = $buyRecord ? $buyRecord['total_buy_times'] : 0; + } + break; + default: { + } + break; + } + + $goodsId = $goodsMeta['goods_id']; + $itemMeta = mt\Item::get($goodsId); + if ($itemMeta) { + // 如果是皮肤,判断是否已经拥有,如果已经拥有,不能购买 + if ($itemMeta['type'] == mt\Item::HERO_SKIN_TYPE) { + $errCode = 0; + $errMsg = ''; + if (!self::canBuy($itemMeta, $errCode, $errMsg)) { + $goods['bought_times'] = 1; + } else { + $goods['bought_times'] = 0; + } + } + } else { + // error !!!!!! + error_log('item not found:' . $goodsId); + } + + if (!empty($goods['free_type'])) { + $count = self::getFreeBuyTimes($goodsMeta['free_type'], + $goodsMeta['id'], + $goodsMeta['goods_id']); + $goodsDto['free_num'] = $goodsDto['free_num'] - $count; + } + } + return $goodsList; + } + + public static function getFreeBuyTimes() + { + return 0; + switch ($free_type) { + case 1: { + $dayTime = myself()->_getNowDaySeconds(); + $sql = 'SELECT COUNT(idx) as cnt FROM t_shop_free_record WHERE account_id = ? AND `id` = ? AND goods_id = ? AND createtime >= ?'; + $row = $conn->execQueryOne($sql, array($account, $id, $goodsId, $dayTime)); + return $row['cnt']; + } + break; + } + + return 0; + } + + public static function buyLimitCheck($goodsMeta, &$errCode, &$errMsg) + { + $errCode = 0; + $errMsg = ''; + $buyRecordHash = ShopBuyRecord::allToHash(); + $boughtTimes = 1; + { + switch ($goodsMeta['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) >= $goodsMeta['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) >= $goodsMeta['limit_num']) { + $this->_rspErr(2, 'Weekly purchase limit reached'); + return; + } + } + break; + case ShopController::TOTAL_BUY_LIMIT: { + // error_log("total buy limit " . $address . " " . $id . " " . $goodsMeta['limit_num']); + $buyRecord = getXVal($buyRecordHash, $id); + $boughtTimes = $buyRecord ? $buyRecord['total_buy_times'] + 1 : 1; + if ($buyRecord && getXVal($buyRecord, 'total_buy_times', 0) >= $goodsMeta['limit_num']) { + $this->_rspErr(2, 'Purchase limit reached'); + return; + } + } + break; + default: { + } + break; + } + } + } + + public static function goodsMetaToInfo($goodsMeta) + { + return array( + + ); + } + + private static 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; + } + +} diff --git a/webapp/services/callback/InAppPurchase.php b/webapp/services/callback/InAppPurchase.php new file mode 100644 index 00000000..5362b1e9 --- /dev/null +++ b/webapp/services/callback/InAppPurchase.php @@ -0,0 +1,207 @@ +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, BUY_SERVER_PKEY); + + 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 = 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']; + if (empty($address)) { + $this->_rspErr(4, "address is empty"); + return; + } + $account_id = $this->getAccountId($address); + if (empty($account_id)) { + $this->_rspErr(5, "account_id is empty"); + return; + } + + 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 = 3; + 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' => 1)); + 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)); + + $id = $order['id']; + $goods = 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']; + if (empty($address)) { + $this->_rspErr(4, "address is empty"); + return; + } + $account_id = $this->getAccountId($address); + if (empty($account_id)) { + $this->_rspErr(5, "account_id is empty"); + return; + } + + if ($item_id == V_ITEM_DIAMOND) { + $event = [ + 'name' => LogService::RECHARGE_DIAMOND, + 'val' => -$item_num + ]; + LogService::productDiamond(['account_id' => $account_id], $event); + } + + $this->_decGoods($address, array( + 'goods_id' => $item_id, + 'goods_num' => $item_num, + 'id' => $id, + )); + break; + default: + $status = 0; + $this->_rspErr(1, "status is not 9 or 96"); + return; + break; + } + } + + $this->_rspOk(); + } + +} diff --git a/webapp/services/callback/ShopBuyGoodsDirect.php b/webapp/services/callback/IutAppPurchase.php similarity index 99% rename from webapp/services/callback/ShopBuyGoodsDirect.php rename to webapp/services/callback/IutAppPurchase.php index 673ded55..b042917f 100644 --- a/webapp/services/callback/ShopBuyGoodsDirect.php +++ b/webapp/services/callback/IutAppPurchase.php @@ -16,8 +16,8 @@ use models\ShopBuyRecord; use services\LogService; -class ShopBuyGoodsDirect -{ +class OutAppPurchase { + public function process() { error_log("buyGoodsDirect --- " . json_encode($_REQUEST)); diff --git a/webapp/services/callback/OutAppPurchase.php b/webapp/services/callback/OutAppPurchase.php new file mode 100644 index 00000000..ea6f0c94 --- /dev/null +++ b/webapp/services/callback/OutAppPurchase.php @@ -0,0 +1,168 @@ +verifySign()) { + error_log("verifySign error --- " . json_encode($_REQUEST)); + myself()->_rspErr(1, 'verifySign error'); + return; + } + $accountId = getReqVal('account_id', ''); + $status = getReqVal('status', ''); + $id = getReqVal('id', ''); + $txhash = getReqVal('txhash', ''); + $sign = getReqVal('sign', ''); + $orderId = getReqVal('order_id', ''); + + $orderDb = OutAppOrder::find($orderId); + if (!$orderDb) { + myself()->_rspErr(2, 'not found order'); + return; + } + if ($orderDb['status'] != OutAppOrder::FINISHED_STATE) { + myself()->_rspErr(0, 'order is finished'); + return; + } + OutAppOrder::markFinished($orderDb['order_id']); + $orderDb = OutAppOrder::find($orderId); + if (!$orderDb) { + myself()->_rspErr(2, 'not found order'); + return; + } + if ($orderDb['status'] == OutAppOrder::FINISHED_STATE) { + myself()->_rspErr(0, 'order is finished'); + return; + } + $buyStatus = 0; // 1: 成功, 2: 失败 + switch ($status) { + case "9": + $buyStatus = 1; + // 充值成功,开始首充奖励 + $this->beginFirstTupop($address); + break; + case "99": + case "98": + $buyStatus = 2; + break; + default: + error_log("buyGoodsDirect--- " . $order_id . " --- " . $status); + $this->_rspErr(1, "status error, status: {$status}"); + break; + } + + if ($buyStatus == 2) { + $this->_rspErr(2, "buyStatus error, buyStatus: {$buyStatus}"); + return; + } + + // 以下是看商品表中是否配置了充值额外奖励 + $goodsMeta = mt\ShopGoods::get($orderDb['goods_id']); + $goodsNum = $orderDb['goods_num']; + $bundleSize = $goodsMeta['bonus_num'] ? $goodsMeta['bonus_num'] : 0; + $itemNum = $goodsNum * $bundleSize; + $itemId = $goodsMeta['bonus']; + $meta = mt\Item::get($itemId); + if ($meta && $itemNum > 0) { + if ($itemId == V_ITEM_DIAMOND) { + $event = [ + 'name' => LogService::RECHARGE_CEBG_BONUS, + 'val' => $itemNum + ]; + LogService::productDiamondCallback( + array( + 'account_id' => $orderDb['account_id'] + ), + $event); + } + + error_log("buyGoodsDirect---" . $address . "---" . $itemId . "---" . $itemNum); + + $this->_addGoods($address, array( + 'goods_id' => $itemId, + 'goods_num' => $itemNum, + 'id' => $id, + )); + } + + $this->_rspOk(); + } + + private function beginFirstTupop($address) + { + $conn = myself()->_getMysql(''); + + $exist = SqlHelper::selectOne( + $conn, + 't_first_topup', + array('address'), + array('address' => $address) + ); + if ($exist) { + return; + } + + // 开始首充奖励活动进程 + $chk = SqlHelper::insert( + $conn, + 't_first_topup', + array( + 'address' => $address, + 'createtime' => myself()->_getNowTime(), + 'status1' => 0, + 'status2' => 0, + 'status3' => 0, + ) + ); + if (!$chk) { + return; + } + } + + + private function verifySign() + { + + } + +}