|
|
@@ -352,6 +352,11 @@ class LakalaAccountService
|
|
|
$application->save();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 平台审核通过:把申请提交到拉卡拉;拉卡拉审核通过后自动刷新回写商户号/终端。
|
|
|
+ * 入参 id 为进件申请主键;成功时返回申请详情。
|
|
|
+ * 花掌柜申请转交 biz-hd,避免沿用销花宝 0.33% 费率。
|
|
|
+ */
|
|
|
public static function platformApprove($id)
|
|
|
{
|
|
|
$application = LakalaApplicationClass::getById($id, true);
|
|
|
@@ -365,12 +370,66 @@ class LakalaAccountService
|
|
|
if ($application->status !== LakalaApplicationClass::STATUS_PLATFORM_AUDIT) {
|
|
|
util::fail('仅后台审核中的申请可以提交拉卡拉');
|
|
|
}
|
|
|
- return self::submit(
|
|
|
+ $result = self::submit(
|
|
|
$application->id,
|
|
|
$application->mainId,
|
|
|
$application->shopId,
|
|
|
self::decode($application->formData)
|
|
|
);
|
|
|
+ if (empty($result)) {
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+ // 提交成功后按拉卡拉审核结果自动刷新,最多 3 次直到本地 APPROVED。
|
|
|
+ return self::refreshAfterPlatformSubmit(
|
|
|
+ $application->id,
|
|
|
+ $application->mainId,
|
|
|
+ $application->shopId,
|
|
|
+ $result
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 平台提交拉卡拉成功后,自动调用与客户端「刷新状态」相同的 refresh。
|
|
|
+ * 拉卡拉审核通过后回写商户号/终端;最多请求 3 次,直到 xhLakalaApplication.status=APPROVED。
|
|
|
+ * 拉卡拉驳回或刷新失败只记日志并返回已有提交结果,不阻断本次审核提交。
|
|
|
+ */
|
|
|
+ private static function refreshAfterPlatformSubmit($id, $mainId, $shopId, $fallback)
|
|
|
+ {
|
|
|
+ $result = $fallback;
|
|
|
+ $maxAttempts = 3;
|
|
|
+ $retryInterval = 3;
|
|
|
+ for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
|
|
|
+ try {
|
|
|
+ $application = LakalaApplicationClass::getById($id, true);
|
|
|
+ if (empty($application)) {
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+ // 已认证通过则无需再刷;拉卡拉已驳回也不会变成 APPROVED,停止重试。
|
|
|
+ if ($application->status === LakalaApplicationClass::STATUS_APPROVED
|
|
|
+ || $application->status === LakalaApplicationClass::STATUS_REJECT) {
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+ // 没有拉卡拉查询主键时 refresh 会直接失败退出,提交后若尚未回写则跳过。
|
|
|
+ $canRefresh = $application->type === LakalaApplicationClass::TYPE_SETTLEMENT_CHANGE
|
|
|
+ ? !empty($application->reviewRelatedId)
|
|
|
+ : (!empty($application->customerNo) || !empty($application->merchantNo));
|
|
|
+ if (!$canRefresh) {
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+ $result = self::refresh($application->id, $application->mainId, $application->shopId);
|
|
|
+ $application = LakalaApplicationClass::getById($id, true);
|
|
|
+ if (!empty($application) && ($application->status === LakalaApplicationClass::STATUS_APPROVED
|
|
|
+ || $application->status === LakalaApplicationClass::STATUS_REJECT)) {
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ Yii::warning('Lakala platformApprove auto refresh attempt ' . $attempt . ' failed: ' . $e->getMessage());
|
|
|
+ }
|
|
|
+ if ($attempt < $maxAttempts) {
|
|
|
+ sleep($retryInterval);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $result;
|
|
|
}
|
|
|
|
|
|
public static function refresh($id, $mainId, $shopId)
|
|
|
@@ -386,7 +445,7 @@ class LakalaAccountService
|
|
|
$client = new LakalaOnboardingClient();
|
|
|
$response = $client->query('/api/v3/tkbs/open_merchant_info', [
|
|
|
'customer_no' => $application->customerNo,
|
|
|
- ], 'both');
|
|
|
+ ], 'both'); //获取商户信息
|
|
|
$customer = $response['data']['customer'];
|
|
|
$status = $customer['customer_status'];
|
|
|
if (in_array($status, ['REJECT', 'REVIEW_FAIL'], true)) {
|
|
|
@@ -526,44 +585,68 @@ class LakalaAccountService
|
|
|
|
|
|
private static function syncTerms($application, $account, $client)
|
|
|
{
|
|
|
- $operations = LakalaOperationClass::getAllByCondition(
|
|
|
- ['applicationId' => $application->id, 'operationType' => 'add_term'],
|
|
|
- null,
|
|
|
- '*',
|
|
|
- null,
|
|
|
- true
|
|
|
- );
|
|
|
- foreach ($operations as $operation) {
|
|
|
- if (!empty($operation->reviewRelatedId) && !in_array($operation->status, ['PASS', 'FAILED'], true)) {
|
|
|
- $review = $client->query('/api/v3/tkbs/customer_update_review', ['review_related_id' => $operation->reviewRelatedId]);
|
|
|
- $operation->status = $review['data']['review_pass'] ?? $operation->status;
|
|
|
- $operation->responseData = self::encode($review);
|
|
|
- $operation->errorMessage = $review['data']['review_result'] ?? '';
|
|
|
- $operation->updateTime = date('Y-m-d H:i:s');
|
|
|
- $operation->save();
|
|
|
+ $maxAttempts = 3;
|
|
|
+ $retryInterval = 3;
|
|
|
+ for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
|
|
|
+ try {
|
|
|
+ $operations = LakalaOperationClass::getAllByCondition(
|
|
|
+ ['applicationId' => $application->id, 'operationType' => 'add_term'],
|
|
|
+ null,
|
|
|
+ '*',
|
|
|
+ null,
|
|
|
+ true
|
|
|
+ );
|
|
|
+ foreach ($operations as $operation) {
|
|
|
+ if (!empty($operation->reviewRelatedId) && !in_array($operation->status, ['PASS', 'FAILED'], true)) {
|
|
|
+ $review = $client->query('/api/v3/tkbs/customer_update_review', ['review_related_id' => $operation->reviewRelatedId]);
|
|
|
+ $operation->status = $review['data']['review_pass'] ?? $operation->status;
|
|
|
+ $operation->responseData = self::encode($review);
|
|
|
+ $operation->errorMessage = $review['data']['review_result'] ?? '';
|
|
|
+ $operation->updateTime = date('Y-m-d H:i:s');
|
|
|
+ $operation->save();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $res = $client->query('/api/v3/tkbs/open_merchant_info', [
|
|
|
+ 'customer_no' => $account->customerNo ?: $application->customerNo,
|
|
|
+ 'merchant_no' => $account->merchantNo ?: $application->merchantNo,
|
|
|
+ ], 'both');
|
|
|
+ $merchantInfo = $res['data'];
|
|
|
+ $customer = $merchantInfo['customer'];
|
|
|
+ $terms = self::merchantInfoTermMap($merchantInfo);
|
|
|
+ $merchantNo = $customer['merchant_no'] ?? '';
|
|
|
+ if ($merchantNo !== '') {
|
|
|
+ $application->merchantNo = $merchantNo;
|
|
|
+ $account->merchantNo = $merchantNo;
|
|
|
+ }
|
|
|
+ self::assignAccountTermNo($account, 'scanTermNo', $terms['scanTermNo'][0] ?? '');
|
|
|
+ self::assignAccountTermNo($account, 'b2bTermNo', $terms['b2BTermNo'][0] ?? '');
|
|
|
+ $account->updateTime = date('Y-m-d H:i:s');
|
|
|
+ $account->save();
|
|
|
+ $application->save();
|
|
|
+ if ($account->scanTermNo != '' && $account->b2bTermNo != '') {
|
|
|
+ LakalaAccountClass::dispatchAuthorizeStatesRefresh([$account->id]);
|
|
|
+ return;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ }
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ Yii::warning('Unable to sync Lakala merchant info terms (attempt ' . $attempt . '): ' . $e->getMessage());
|
|
|
}
|
|
|
- }
|
|
|
- try {
|
|
|
- $res = $client->query('/api/v3/tkbs/open_merchant_info', [
|
|
|
- 'customer_no' => $account->customerNo ?: $application->customerNo,
|
|
|
- 'merchant_no' => $account->merchantNo ?: $application->merchantNo,
|
|
|
- ], 'both');
|
|
|
- $merchantInfo = $res['data'];
|
|
|
- $customer = $merchantInfo['customer'];
|
|
|
- $terms = self::merchantInfoTermMap($merchantInfo);
|
|
|
- $merchantNo = $customer['merchant_no'] ?? '';
|
|
|
- if ($merchantNo !== '') {
|
|
|
- $application->merchantNo = $merchantNo;
|
|
|
- $account->merchantNo = $merchantNo;
|
|
|
+ if ($attempt < $maxAttempts) {
|
|
|
+ sleep($retryInterval);
|
|
|
}
|
|
|
- $account->scanTermNo = $terms['scanTermNo'][0] ?? $account->scanTermNo;
|
|
|
- $account->b2bTermNo = $terms['b2BTermNo'][0] ?? $account->b2bTermNo;
|
|
|
- $account->updateTime = date('Y-m-d H:i:s');
|
|
|
- $account->save();
|
|
|
- $application->save();
|
|
|
- LakalaAccountClass::dispatchAuthorizeStatesRefresh([$account->id]);
|
|
|
- } catch (\Throwable $e) {
|
|
|
- Yii::warning('Unable to sync Lakala merchant info terms: ' . $e->getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * scanTermNo / b2bTermNo 为 NOT NULL,拉卡拉尚未返回终端号时不能写成 null,否则 save 会 1048。
|
|
|
+ */
|
|
|
+ private static function assignAccountTermNo($account, $attribute, $termNo)
|
|
|
+ {
|
|
|
+ $termNo = trim((string)$termNo);
|
|
|
+ if ($termNo !== '') {
|
|
|
+ $account->$attribute = $termNo;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -933,10 +1016,14 @@ class LakalaAccountService
|
|
|
private static function version($application, array $request, array $response)
|
|
|
{
|
|
|
LakalaApplicationVersionClass::add([
|
|
|
- 'applicationId' => $application->id, 'mainId' => $application->mainId,
|
|
|
- 'versionNo' => $application->versionNo, 'type' => $application->type,
|
|
|
- 'formData' => $application->formData, 'requestData' => self::encode($request),
|
|
|
- 'responseData' => self::encode($response), 'createTime' => date('Y-m-d H:i:s'),
|
|
|
+ 'applicationId' => $application->id,
|
|
|
+ 'mainId' => $application->mainId,
|
|
|
+ 'versionNo' => $application->versionNo,
|
|
|
+ 'type' => $application->type,
|
|
|
+ 'formData' => $application->formData,
|
|
|
+ 'requestData' => self::encode($request),
|
|
|
+ 'responseData' => self::encode($response),
|
|
|
+ 'createTime' => date('Y-m-d H:i:s'),
|
|
|
]);
|
|
|
}
|
|
|
|
|
|
@@ -973,13 +1060,19 @@ class LakalaAccountService
|
|
|
$terminalInfos = $value['terminal_info'] ?? [];
|
|
|
foreach ($terminalInfos as $term) {
|
|
|
if (($term['term_type_name'] ?? '') == '专业化扫码') {
|
|
|
- $result['scanTermNo'][] = $term['active_no_vo_list'][0]['term_no'] ?? '';
|
|
|
+ $termNo = trim((string)($term['active_no_vo_list'][0]['term_no'] ?? ''));
|
|
|
+ if ($termNo !== '') {
|
|
|
+ $result['scanTermNo'][] = $termNo;
|
|
|
+ }
|
|
|
}
|
|
|
if (($term['term_type_name'] ?? '') == '聚合收银台') {
|
|
|
$list = $term['active_no_vo_list'] ?? [];
|
|
|
foreach ($list as $item) {
|
|
|
if (($item['busi_type_code'] ?? '') == 'QR_CODE_CARD') {
|
|
|
- $result['b2BTermNo'][] = $item['term_no'] ?? '';
|
|
|
+ $termNo = trim((string)($item['term_no'] ?? ''));
|
|
|
+ if ($termNo !== '') {
|
|
|
+ $result['b2BTermNo'][] = $termNo;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|