This commit is contained in:
azw 2023-07-30 15:36:11 +08:00
parent 3de0044afe
commit 153c9262fe
4 changed files with 228 additions and 209 deletions

View File

@ -7,6 +7,10 @@ use phpcommon\SqlHelper;
class InAppOrder extends BaseModel {
const PENDING_STATE = 0;
const FINISHED_STATE = 1;
const FAILED_STATE = 2;
public static function find($orderId) {
$row = SqlHelper::ormSelectOne(
myself()->_get(),

View File

@ -7,4 +7,34 @@ use phpcommon\SqlHelper;
class OutAppOrder extends BaseModel {
const PENDING_STATE = 0;
const FINISHED_STATE = 1;
const FAILED_STATE = 2;
public static function find($orderId)
{
$row = SqlHelper::ormSelectOne(
myself()->_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,
)
);
}
}

View File

@ -20,42 +20,50 @@ class InAppPurchase {
public function process()
{
error_log("buyGoodsDirect --- " . json_encode($_REQUEST));
error_log('ShopInappPurchaseDiamonds:' . json_encode($_REQUEST, JSON_PRETTY_PRINT));
error_log('----- inappPurchaseDiamonds -----');
$body = json_decode(file_get_contents('php://input'), true);
error_log('body:' . json_encode($body));
$channel = $body['channel'];
$records = $body['records'];
$sign = $body['sign'];
// 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是
// PENDING = 0, // 初始状态
// TRANSFERING = 1, //只有国库模式才会有该状态
// TRANSFERED = 2, //只有国库模式才会有该状态
// SUCCESS = 9, // 成功的最终状态
// TRANSFER_FAIL = 98, // 转账错误
// FAIL = 99, // 也是错误
//
// {
// 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 = ''
// const signStr = 'channel=google&' + records.map(record =>Object.keys(record).sort().map(key => `${key}=${record[key]}`).join('&')).join('&')
$account_id = getReqVal('account_id', '');
$order_id = getReqVal('order_id', '');
$status = getReqVal('status', '');
$id = getReqVal('id', '');
$txhash = getReqVal('txhash', '');
// const sign = hmacsha256(signStr, hashSort)
$sign = getReqVal('sign', '');
// 定义一个空数组,用来存放每个记录的键值对字符串
$record_strings = array();
$data = array(
'account_id' => $account_id,
'id' => $id,
'order_id' => $order_id,
'status' => $status,
'txhash' => $txhash,
);
// 遍历 records 数组,对每个记录进行排序和拼接
foreach ($records as $record) {
// 对记录的键进行升序排序
ksort($record);
// 把记录的键值对用等号连接,然后用 & 连接成一个字符串
$record_string = http_build_query($record);
// 把字符串加入到 record_strings 数组中
$record_strings[] = $record_string;
}
$hash_data = http_build_query($data);
// 把 record_strings 数组用 & 连接成一个字符串
$records_string = implode("&", $record_strings);
$hash_data = 'channel=' . $channel . '&' . $records_string;
$signature = hash_hmac('sha256', $hash_data, BUY_SERVER_PKEY);
@ -64,163 +72,136 @@ class InAppPurchase {
return;
}
error_log("buyGoodsDirect-------" . $order_id . "---" . $status);
$conn = myself()->_getMysql('');
// 有三种情况:
// 1. 从商城购买钻石,有订单号
// 2. 站外充值钻石,没有订单号
// 3. appstore 退款,没有订单号
$order = SqlHelper::selectOne($conn, 't_shop_buy_order', array('address', 'id', 'item_id', 'goods_num', 'status'), array('order_id' => $order_id));
if (!$order) {
$this->_rspErr(2, "order not found: {$order_id}");
return;
}
for ($i = 0; $i < count($records); $i++) {
$record = $records[$i];
$id = $order['id'];
$goods_num = $order['goods_num'];
$o_status = $order['status'];
$address = $order['address'];
$product_id = $record['productId'];
$order_id = $record['gameOrderId'];
$out_order_id = $record['orderId'];
$status = $record['status'];
if ($o_status != 0) {
$this->_rspErr(1, "order status error, status: {$o_status}");
return;
}
switch ($status) {
case 9: {
$status = 1;
if (empty($order_id)) {
if (empty($product_id)) {
$this->_rspErr(2, "product_id is empty");
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;
}
// $goods = mt\ShopGoods::getByProductId($product_id);
SqlHelper::update($conn, 't_shop_buy_order', array('order_id' => $order_id), array('status' => $buyStatus));
return;
}
if ($buyStatus == 2) {
$this->_rspErr(2, "buyStatus error, buyStatus: {$buyStatus}");
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;
}
// 以下是看商品表中是否配置了充值额外奖励
$goods = ShopGoods::get($id);
error_log("buyGoodsDirect---" . json_encode($goods));
$goods_num = $order['goods_num'];
$bundle_size = $goods['bonus_num'] ? $goods['bonus_num'] : 0;
$item_num = $goods_num * $bundle_size;
$item_id = $goods['bonus'];
$meta = Item::get($item_id);
error_log("buyGoodsDirect---" . $item_id . "---" . $item_num . "---" . $bundle_size . "---" . $meta['name']);
if ($meta && $item_num > 0) {
// $address = $order['address'];
$account_id = $this->getAccountId($address);
SqlHelper::update($conn, 't_web2_order', array('order_id' => $order_id), array('status' => $status, 'channel' => $channel, 'out_order_id' => $out_order_id));
if ($item_id == V_ITEM_DIAMOND) {
$event = [
'name' => LogService::RECHARGE_CEBG_BONUS,
'val' => $item_num
];
LogService::productDiamondCallback(['account_id' => $account_id], $event);
$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;
}
error_log("buyGoodsDirect---" . $address . "---" . $item_id . "---" . $item_num);
$this->_addGoods($address, array(
'goods_id' => $item_id,
'goods_num' => $item_num,
'id' => $id,
));
}
$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('_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);
}
}
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 _rspOk()
{
echo json_encode(array(
'errcode' => 0,
'errmsg' => "callback success",
));
}
private function _rspErr($errcode, $errmsg)
{
if (SERVER_ENV != _ONLINE) {
error_log(json_encode(array(
'errcode' => $errcode,
'errmsg' => $errmsg,
)));
}
echo json_encode(array(
'errcode' => $errcode,
'errmsg' => $errmsg,
));
}
}

View File

@ -4,7 +4,10 @@ namespace services;
require_once("mt/ShopGoods.php");
require_once("mt/Item.php");
require_once("models/ShopBuyRecord.php");
require_once("models/OutAppOrder.php");
require_once("services/LogService.php");
require_once("ShopAddItemService.php");
@ -12,7 +15,9 @@ use phpcommon\SqlHelper;
use mt\ShopGoods;
use mt\Item;
use models\ShopBuyRecord;
use models\OutAppOrder;
use services\LogService;
@ -29,61 +34,54 @@ class OutAppPurchase {
// id: string
// txhash: string
// }
// 我返回给你这些数据和一个sign字段,
// sign使用上面 repdata 按key 顺序排后, 组成key1=val1&key2=val2后, 使用hmac_sha256 hash, key是
// 我返回给你这些数据和一个sign字段,
// sign使用上面 repdata 按key 顺序排后, 组成key1=val1&key2=val2后, 使用hmac_sha256 hash, key是
// PENDING = 0, // 初始状态
// TRANSFERING = 1, //只有国库模式才会有该状态
// TRANSFERED = 2, //只有国库模式才会有该状态
// SUCCESS = 9, // 成功的最终状态
// TRANSFER_FAIL = 98, // 转账错误
// FAIL = 99, // 也是错误
//
$account_id = getReqVal('account_id', '');
$order_id = getReqVal('order_id', '');
//
if (!$this->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', '');
$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, BUY_SERVER_PKEY);
if ($signature != $sign) {
$this->_rspErr(1, "signature error, signature: {$signature}, sign: {$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;
}
error_log("buyGoodsDirect-------" . $order_id . "---" . $status);
$conn = myself()->_getMysql('');
$order = SqlHelper::selectOne($conn, 't_shop_buy_order', array('address', 'id', 'item_id', 'goods_num', 'status'), array('order_id' => $order_id));
if (!$order) {
$this->_rspErr(2, "order not found: {$order_id}");
return;
}
$id = $order['id'];
$goods_num = $order['goods_num'];
$o_status = $order['status'];
$address = $order['address'];
if ($o_status != 0) {
$this->_rspErr(1, "order status error, status: {$o_status}");
return;
}
$buyStatus = 0; // 1: 成功, 2: 失败
switch ($status) {
case "9":
@ -190,4 +188,10 @@ class OutAppPurchase {
}
}
private function verifySign()
{
}
}