mirror of
https://gitee.com/technical-laohu/mpay_v2_webman.git
synced 2026-04-04 09:04:26 +08:00
更新
This commit is contained in:
@@ -116,18 +116,18 @@ class ChannelController extends BaseController
|
||||
}
|
||||
|
||||
$channelData = [
|
||||
'merchant_id' => $merchantId,
|
||||
'merchant_app_id' => $merchantAppId,
|
||||
'mer_id' => $merchantId,
|
||||
'app_id' => $merchantAppId,
|
||||
'chan_code' => $channelCode !== '' ? $channelCode : 'CH' . date('YmdHis') . mt_rand(1000, 9999),
|
||||
'chan_name' => $channelName,
|
||||
'plugin_code' => $pluginCode,
|
||||
'method_id' => (int)$method->id,
|
||||
'config_json' => array_merge($configJson, [
|
||||
'pay_type_id' => (int)$method->id,
|
||||
'config' => array_merge($configJson, [
|
||||
'enabled_products' => is_array($enabledProducts) ? array_values($enabledProducts) : [],
|
||||
]),
|
||||
'split_ratio' => isset($data['split_ratio']) ? (float)$data['split_ratio'] : 100,
|
||||
'chan_cost' => isset($data['channel_cost']) ? (float)$data['channel_cost'] : 0,
|
||||
'chan_mode' => trim((string)($data['channel_mode'] ?? 'wallet')) ?: 'wallet',
|
||||
'chan_mode' => in_array(strtolower(trim((string)($data['channel_mode'] ?? 'wallet'))), ['1', 'direct', 'merchant'], true) ? 1 : 0,
|
||||
'daily_limit' => isset($data['daily_limit']) ? (float)$data['daily_limit'] : 0,
|
||||
'daily_cnt' => isset($data['daily_count']) ? (int)$data['daily_count'] : 0,
|
||||
'min_amount' => isset($data['min_amount']) && $data['min_amount'] !== '' ? (float)$data['min_amount'] : null,
|
||||
@@ -648,4 +648,4 @@ class ChannelController extends BaseController
|
||||
}
|
||||
return $summary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,9 +34,8 @@ class MerchantAppController extends BaseController
|
||||
$packageMap = $this->buildPackageMap();
|
||||
$items = [];
|
||||
foreach ($paginator->items() as $row) {
|
||||
$item = (array)$row;
|
||||
$config = $this->getConfigObject($this->appConfigKey((int)($item['id'] ?? 0)));
|
||||
$packageCode = trim((string)($config['package_code'] ?? ''));
|
||||
$item = method_exists($row, 'toArray') ? $row->toArray() : (array)$row;
|
||||
$packageCode = trim((string)($item['package_code'] ?? ''));
|
||||
$item['package_code'] = $packageCode;
|
||||
$item['package_name'] = $packageCode !== '' ? ($packageMap[$packageCode] ?? $packageCode) : '';
|
||||
$items[] = $item;
|
||||
@@ -62,7 +61,7 @@ class MerchantAppController extends BaseController
|
||||
return $this->fail('app not found', 404);
|
||||
}
|
||||
|
||||
return $this->success($row);
|
||||
return $this->success(method_exists($row, 'toArray') ? $row->toArray() : (array)$row);
|
||||
}
|
||||
|
||||
public function configDetail(Request $request)
|
||||
@@ -77,7 +76,8 @@ class MerchantAppController extends BaseController
|
||||
return $this->fail('app not found', 404);
|
||||
}
|
||||
|
||||
$config = array_merge($this->defaultAppConfig(), $this->getConfigObject($this->appConfigKey($id)));
|
||||
$appRow = method_exists($app, 'toArray') ? $app->toArray() : (array)$app;
|
||||
$config = $this->buildAppConfig($appRow);
|
||||
return $this->success([
|
||||
'app' => $app,
|
||||
'config' => $config,
|
||||
@@ -122,11 +122,12 @@ class MerchantAppController extends BaseController
|
||||
}
|
||||
|
||||
$update = [
|
||||
'merchant_id' => $merchantId,
|
||||
'mer_id' => $merchantId,
|
||||
'api_type' => $apiType,
|
||||
'app_id' => $appId,
|
||||
'app_code' => $appId,
|
||||
'app_name' => $appName,
|
||||
'status' => $status,
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
if (!empty($data['app_secret'])) {
|
||||
@@ -142,12 +143,14 @@ class MerchantAppController extends BaseController
|
||||
|
||||
$secret = !empty($data['app_secret']) ? (string)$data['app_secret'] : $this->generateSecret();
|
||||
$this->merchantAppRepository->create([
|
||||
'merchant_id' => $merchantId,
|
||||
'mer_id' => $merchantId,
|
||||
'api_type' => $apiType,
|
||||
'app_id' => $appId,
|
||||
'app_code' => $appId,
|
||||
'app_secret' => $secret,
|
||||
'app_name' => $appName,
|
||||
'status' => $status,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -236,8 +239,9 @@ class MerchantAppController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
$stored = array_merge($this->defaultAppConfig(), $this->getConfigObject($this->appConfigKey($id)), $config);
|
||||
$this->systemConfigService->setValue($this->appConfigKey($id), $stored);
|
||||
$updateData = $config;
|
||||
$updateData['updated_at'] = date('Y-m-d H:i:s');
|
||||
$this->merchantAppRepository->updateById($id, $updateData);
|
||||
|
||||
return $this->success(null, 'saved');
|
||||
}
|
||||
@@ -248,42 +252,6 @@ class MerchantAppController extends BaseController
|
||||
return rtrim(strtr(base64_encode($raw), '+/', '-_'), '=');
|
||||
}
|
||||
|
||||
private function appConfigKey(int $appId): string
|
||||
{
|
||||
return 'merchant_app_config_' . $appId;
|
||||
}
|
||||
|
||||
private function defaultAppConfig(): array
|
||||
{
|
||||
return [
|
||||
'package_code' => '',
|
||||
'notify_url' => '',
|
||||
'return_url' => '',
|
||||
'callback_mode' => 'server',
|
||||
'sign_type' => 'md5',
|
||||
'order_expire_minutes' => 30,
|
||||
'callback_retry_limit' => 6,
|
||||
'ip_whitelist' => '',
|
||||
'amount_min' => 0,
|
||||
'amount_max' => 0,
|
||||
'daily_limit' => 0,
|
||||
'notify_enabled' => 1,
|
||||
'remark' => '',
|
||||
'updated_at' => '',
|
||||
];
|
||||
}
|
||||
|
||||
private function getConfigObject(string $configKey): array
|
||||
{
|
||||
$raw = $this->systemConfigService->getValue($configKey, '{}');
|
||||
if (!is_string($raw) || $raw === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$decoded = json_decode($raw, true);
|
||||
return is_array($decoded) ? $decoded : [];
|
||||
}
|
||||
|
||||
private function getConfigEntries(string $configKey): array
|
||||
{
|
||||
$raw = $this->systemConfigService->getValue($configKey, '[]');
|
||||
@@ -299,6 +267,26 @@ class MerchantAppController extends BaseController
|
||||
return array_values(array_filter($decoded, 'is_array'));
|
||||
}
|
||||
|
||||
private function buildAppConfig(array $app): array
|
||||
{
|
||||
return [
|
||||
'package_code' => trim((string)($app['package_code'] ?? '')),
|
||||
'notify_url' => trim((string)($app['notify_url'] ?? '')),
|
||||
'return_url' => trim((string)($app['return_url'] ?? '')),
|
||||
'callback_mode' => trim((string)($app['callback_mode'] ?? 'server')) ?: 'server',
|
||||
'sign_type' => trim((string)($app['sign_type'] ?? 'md5')) ?: 'md5',
|
||||
'order_expire_minutes' => (int)($app['order_expire_minutes'] ?? 30),
|
||||
'callback_retry_limit' => (int)($app['callback_retry_limit'] ?? 6),
|
||||
'ip_whitelist' => trim((string)($app['ip_whitelist'] ?? '')),
|
||||
'amount_min' => (string)($app['amount_min'] ?? '0.00'),
|
||||
'amount_max' => (string)($app['amount_max'] ?? '0.00'),
|
||||
'daily_limit' => (string)($app['daily_limit'] ?? '0.00'),
|
||||
'notify_enabled' => (int)($app['notify_enabled'] ?? 1),
|
||||
'remark' => trim((string)($app['remark'] ?? '')),
|
||||
'updated_at' => (string)($app['updated_at'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
private function buildPackageMap(): array
|
||||
{
|
||||
$map = [];
|
||||
|
||||
@@ -25,18 +25,15 @@ class MerchantController extends BaseController
|
||||
'status' => $request->get('status', ''),
|
||||
'merchant_no' => trim((string)$request->get('merchant_no', '')),
|
||||
'merchant_name' => trim((string)$request->get('merchant_name', '')),
|
||||
'email' => trim((string)$request->get('email', '')),
|
||||
'balance' => trim((string)$request->get('balance', '')),
|
||||
];
|
||||
|
||||
$paginator = $this->merchantRepository->searchPaginate($filters, $page, $pageSize);
|
||||
$groupMap = $this->buildGroupMap();
|
||||
$items = [];
|
||||
foreach ($paginator->items() as $row) {
|
||||
$item = (array)$row;
|
||||
$profile = $this->getConfigObject($this->merchantProfileKey((int)($item['id'] ?? 0)));
|
||||
$groupCode = trim((string)($profile['group_code'] ?? ''));
|
||||
$item['group_code'] = $groupCode;
|
||||
$item['group_name'] = $groupCode !== '' ? ($groupMap[$groupCode] ?? $groupCode) : '';
|
||||
$items[] = $item;
|
||||
$item = method_exists($row, 'toArray') ? $row->toArray() : (array)$row;
|
||||
$items[] = $this->normalizeMerchantRow($item);
|
||||
}
|
||||
|
||||
return $this->success([
|
||||
@@ -59,7 +56,8 @@ class MerchantController extends BaseController
|
||||
return $this->fail('merchant not found', 404);
|
||||
}
|
||||
|
||||
return $this->success($row);
|
||||
$merchant = method_exists($row, 'toArray') ? $row->toArray() : (array)$row;
|
||||
return $this->success($this->normalizeMerchantRow($merchant));
|
||||
}
|
||||
|
||||
public function profileDetail(Request $request)
|
||||
@@ -74,10 +72,10 @@ class MerchantController extends BaseController
|
||||
return $this->fail('merchant not found', 404);
|
||||
}
|
||||
|
||||
$profile = array_merge($this->defaultMerchantProfile(), $this->getConfigObject($this->merchantProfileKey($id)));
|
||||
$merchantRow = method_exists($merchant, 'toArray') ? $merchant->toArray() : (array)$merchant;
|
||||
return $this->success([
|
||||
'merchant' => $merchant,
|
||||
'profile' => $profile,
|
||||
'merchant' => $this->normalizeMerchantRow($merchantRow),
|
||||
'profile' => $this->buildMerchantProfile($merchantRow),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -88,23 +86,24 @@ class MerchantController extends BaseController
|
||||
|
||||
$merchantNo = trim((string)($data['merchant_no'] ?? ''));
|
||||
$merchantName = trim((string)($data['merchant_name'] ?? ''));
|
||||
$fundsMode = trim((string)($data['funds_mode'] ?? 'direct'));
|
||||
$balance = max(0, (float)($data['balance'] ?? 0));
|
||||
$email = trim((string)($data['email'] ?? $data['notify_email'] ?? ''));
|
||||
$status = (int)($data['status'] ?? 1);
|
||||
$remark = trim((string)($data['remark'] ?? ''));
|
||||
|
||||
if ($merchantNo === '' || $merchantName === '') {
|
||||
return $this->fail('merchant_no and merchant_name are required', 400);
|
||||
}
|
||||
|
||||
if (!in_array($fundsMode, ['direct', 'wallet', 'hybrid'], true)) {
|
||||
return $this->fail('invalid funds_mode', 400);
|
||||
}
|
||||
|
||||
if ($id > 0) {
|
||||
$this->merchantRepository->updateById($id, [
|
||||
'merchant_no' => $merchantNo,
|
||||
'merchant_name' => $merchantName,
|
||||
'funds_mode' => $fundsMode,
|
||||
'balance' => $balance,
|
||||
'email' => $email,
|
||||
'status' => $status,
|
||||
'remark' => $remark,
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
} else {
|
||||
$exists = $this->merchantRepository->findByMerchantNo($merchantNo);
|
||||
@@ -115,8 +114,12 @@ class MerchantController extends BaseController
|
||||
$this->merchantRepository->create([
|
||||
'merchant_no' => $merchantNo,
|
||||
'merchant_name' => $merchantName,
|
||||
'funds_mode' => $fundsMode,
|
||||
'balance' => $balance,
|
||||
'email' => $email,
|
||||
'status' => $status,
|
||||
'remark' => $remark,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -148,46 +151,17 @@ class MerchantController extends BaseController
|
||||
return $this->fail('merchant not found', 404);
|
||||
}
|
||||
|
||||
$riskLevel = trim((string)$request->post('risk_level', 'standard'));
|
||||
$settlementCycle = trim((string)$request->post('settlement_cycle', 't1'));
|
||||
if (!in_array($riskLevel, ['low', 'standard', 'high'], true)) {
|
||||
return $this->fail('invalid risk_level', 400);
|
||||
}
|
||||
if (!in_array($settlementCycle, ['d0', 't1', 'manual'], true)) {
|
||||
return $this->fail('invalid settlement_cycle', 400);
|
||||
}
|
||||
$merchantRow = method_exists($merchant, 'toArray') ? $merchant->toArray() : (array)$merchant;
|
||||
|
||||
$profile = [
|
||||
'group_code' => trim((string)$request->post('group_code', '')),
|
||||
'contact_name' => trim((string)$request->post('contact_name', '')),
|
||||
'contact_phone' => trim((string)$request->post('contact_phone', '')),
|
||||
'notify_email' => trim((string)$request->post('notify_email', '')),
|
||||
'callback_domain' => trim((string)$request->post('callback_domain', '')),
|
||||
'callback_ip_whitelist' => trim((string)$request->post('callback_ip_whitelist', '')),
|
||||
'risk_level' => $riskLevel,
|
||||
'single_limit' => max(0, (float)$request->post('single_limit', 0)),
|
||||
'daily_limit' => max(0, (float)$request->post('daily_limit', 0)),
|
||||
'settlement_cycle' => $settlementCycle,
|
||||
'tech_support' => trim((string)$request->post('tech_support', '')),
|
||||
'email' => trim((string)$request->post('email', $request->post('notify_email', ''))),
|
||||
'remark' => trim((string)$request->post('remark', '')),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
'balance' => max(0, (float)$request->post('balance', $merchantRow['balance'] ?? 0)),
|
||||
];
|
||||
|
||||
if ($profile['group_code'] !== '') {
|
||||
$groupExists = false;
|
||||
foreach ($this->getConfigEntries('merchant_groups') as $group) {
|
||||
if (($group['group_code'] ?? '') === $profile['group_code']) {
|
||||
$groupExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$groupExists) {
|
||||
return $this->fail('group_code not found', 400);
|
||||
}
|
||||
}
|
||||
|
||||
$stored = array_merge($this->defaultMerchantProfile(), $this->getConfigObject($this->merchantProfileKey($merchantId)), $profile);
|
||||
$this->systemConfigService->setValue($this->merchantProfileKey($merchantId), $stored);
|
||||
$updateData = $profile;
|
||||
$updateData['updated_at'] = date('Y-m-d H:i:s');
|
||||
$this->merchantRepository->updateById($merchantId, $updateData);
|
||||
|
||||
return $this->success(null, 'saved');
|
||||
}
|
||||
@@ -198,9 +172,9 @@ class MerchantController extends BaseController
|
||||
$pageSize = (int)$request->get('page_size', 10);
|
||||
$filters = $this->buildOpFilters($request);
|
||||
|
||||
$summaryQuery = Db::table('ma_merchant as m')
|
||||
->leftJoin('ma_merchant_app as ma', 'ma.merchant_id', '=', 'm.id')
|
||||
->leftJoin('ma_pay_channel as pc', 'pc.merchant_id', '=', 'm.id')
|
||||
$summaryQuery = Db::table('ma_mer as m')
|
||||
->leftJoin('ma_pay_app as ma', 'ma.mer_id', '=', 'm.id')
|
||||
->leftJoin('ma_pay_channel as pc', 'pc.mer_id', '=', 'm.id')
|
||||
->leftJoin('ma_pay_order as o', function ($join) use ($filters) {
|
||||
$join->on('o.merchant_id', '=', 'm.id');
|
||||
if (!empty($filters['created_from'])) {
|
||||
@@ -225,9 +199,9 @@ class MerchantController extends BaseController
|
||||
)
|
||||
->first();
|
||||
|
||||
$listQuery = Db::table('ma_merchant as m')
|
||||
->leftJoin('ma_merchant_app as ma', 'ma.merchant_id', '=', 'm.id')
|
||||
->leftJoin('ma_pay_channel as pc', 'pc.merchant_id', '=', 'm.id')
|
||||
$listQuery = Db::table('ma_mer as m')
|
||||
->leftJoin('ma_pay_app as ma', 'ma.mer_id', '=', 'm.id')
|
||||
->leftJoin('ma_pay_channel as pc', 'pc.mer_id', '=', 'm.id')
|
||||
->leftJoin('ma_pay_order as o', function ($join) use ($filters) {
|
||||
$join->on('o.merchant_id', '=', 'm.id');
|
||||
if (!empty($filters['created_from'])) {
|
||||
@@ -241,7 +215,7 @@ class MerchantController extends BaseController
|
||||
|
||||
$paginator = $listQuery
|
||||
->selectRaw(
|
||||
'm.id, m.merchant_no, m.merchant_name, m.funds_mode, m.status, m.created_at,
|
||||
'm.id, m.merchant_no, m.merchant_name, m.balance, m.email, m.status, m.remark, m.created_at,
|
||||
COUNT(DISTINCT ma.id) AS app_count,
|
||||
COUNT(DISTINCT CASE WHEN ma.status = 1 THEN ma.id END) AS active_app_count,
|
||||
COUNT(DISTINCT pc.id) AS channel_count,
|
||||
@@ -252,7 +226,7 @@ class MerchantController extends BaseController
|
||||
COALESCE(SUM(CASE WHEN o.status = 1 THEN o.fee ELSE 0 END), 0) AS fee_amount,
|
||||
MAX(o.created_at) AS last_order_at'
|
||||
)
|
||||
->groupBy('m.id', 'm.merchant_no', 'm.merchant_name', 'm.funds_mode', 'm.status', 'm.created_at')
|
||||
->groupBy('m.id', 'm.merchant_no', 'm.merchant_name', 'm.balance', 'm.email', 'm.status', 'm.remark', 'm.created_at')
|
||||
->orderByDesc('m.id')
|
||||
->paginate($pageSize, ['*'], 'page', $page);
|
||||
|
||||
@@ -280,7 +254,7 @@ class MerchantController extends BaseController
|
||||
$pageSize = (int)$request->get('page_size', 10);
|
||||
$filters = $this->buildOpFilters($request);
|
||||
|
||||
$summaryQuery = Db::table('ma_merchant as m')
|
||||
$summaryQuery = Db::table('ma_mer as m')
|
||||
->leftJoin('ma_pay_order as o', function ($join) use ($filters) {
|
||||
$join->on('o.merchant_id', '=', 'm.id');
|
||||
if (!empty($filters['created_from'])) {
|
||||
@@ -303,7 +277,7 @@ class MerchantController extends BaseController
|
||||
)
|
||||
->first();
|
||||
|
||||
$listQuery = Db::table('ma_merchant as m')
|
||||
$listQuery = Db::table('ma_mer as m')
|
||||
->leftJoin('ma_pay_order as o', function ($join) use ($filters) {
|
||||
$join->on('o.merchant_id', '=', 'm.id');
|
||||
if (!empty($filters['created_from'])) {
|
||||
@@ -317,7 +291,7 @@ class MerchantController extends BaseController
|
||||
|
||||
$paginator = $listQuery
|
||||
->selectRaw(
|
||||
'm.id, m.merchant_no, m.merchant_name, m.funds_mode, m.status, m.created_at,
|
||||
'm.id, m.merchant_no, m.merchant_name, m.balance, m.email, m.status, m.remark, m.created_at,
|
||||
COUNT(DISTINCT CASE WHEN o.status = 1 THEN o.id END) AS success_order_count,
|
||||
COUNT(DISTINCT CASE WHEN o.status = 0 THEN o.id END) AS pending_order_count,
|
||||
COUNT(DISTINCT CASE WHEN o.notify_stat = 0 THEN o.id END) AS notify_pending_orders,
|
||||
@@ -327,7 +301,7 @@ class MerchantController extends BaseController
|
||||
COALESCE(SUM(CASE WHEN o.status = 1 THEN o.real_amount - o.fee ELSE 0 END), 0) AS net_amount,
|
||||
MAX(o.pay_at) AS last_pay_at'
|
||||
)
|
||||
->groupBy('m.id', 'm.merchant_no', 'm.merchant_name', 'm.funds_mode', 'm.status', 'm.created_at')
|
||||
->groupBy('m.id', 'm.merchant_no', 'm.merchant_name', 'm.balance', 'm.email', 'm.status', 'm.remark', 'm.created_at')
|
||||
->orderByRaw('COALESCE(SUM(CASE WHEN o.status = 1 THEN o.real_amount - o.fee ELSE 0 END), 0) DESC')
|
||||
->paginate($pageSize, ['*'], 'page', $page);
|
||||
|
||||
@@ -354,7 +328,7 @@ class MerchantController extends BaseController
|
||||
$auditStatus = trim((string)$request->get('audit_status', ''));
|
||||
$keyword = trim((string)$request->get('keyword', ''));
|
||||
|
||||
$summaryQuery = Db::table('ma_merchant as m');
|
||||
$summaryQuery = Db::table('ma_mer as m');
|
||||
if ($keyword !== '') {
|
||||
$summaryQuery->where(function ($query) use ($keyword) {
|
||||
$query->where('m.merchant_no', 'like', '%' . $keyword . '%')
|
||||
@@ -375,8 +349,8 @@ class MerchantController extends BaseController
|
||||
)
|
||||
->first();
|
||||
|
||||
$listQuery = Db::table('ma_merchant as m')
|
||||
->leftJoin('ma_merchant_app as ma', 'ma.merchant_id', '=', 'm.id');
|
||||
$listQuery = Db::table('ma_mer as m')
|
||||
->leftJoin('ma_pay_app as ma', 'ma.mer_id', '=', 'm.id');
|
||||
if ($keyword !== '') {
|
||||
$listQuery->where(function ($query) use ($keyword) {
|
||||
$query->where('m.merchant_no', 'like', '%' . $keyword . '%')
|
||||
@@ -391,12 +365,12 @@ class MerchantController extends BaseController
|
||||
|
||||
$paginator = $listQuery
|
||||
->selectRaw(
|
||||
'm.id, m.merchant_no, m.merchant_name, m.funds_mode, m.status, m.created_at, m.updated_at,
|
||||
'm.id, m.merchant_no, m.merchant_name, m.balance, m.email, m.status, m.remark, m.created_at, m.updated_at,
|
||||
COUNT(DISTINCT ma.id) AS app_count,
|
||||
COUNT(DISTINCT CASE WHEN ma.status = 1 THEN ma.id END) AS active_app_count,
|
||||
COUNT(DISTINCT CASE WHEN ma.status = 0 THEN ma.id END) AS disabled_app_count'
|
||||
)
|
||||
->groupBy('m.id', 'm.merchant_no', 'm.merchant_name', 'm.funds_mode', 'm.status', 'm.created_at', 'm.updated_at')
|
||||
->groupBy('m.id', 'm.merchant_no', 'm.merchant_name', 'm.balance', 'm.email', 'm.status', 'm.remark', 'm.created_at', 'm.updated_at')
|
||||
->orderBy('m.status', 'asc')
|
||||
->orderByDesc('m.id')
|
||||
->paginate($pageSize, ['*'], 'page', $page);
|
||||
@@ -433,11 +407,11 @@ class MerchantController extends BaseController
|
||||
|
||||
$status = $action === 'approve' ? 1 : 0;
|
||||
Db::connection()->transaction(function () use ($id, $status) {
|
||||
Db::table('ma_merchant')->where('id', $id)->update([
|
||||
Db::table('ma_mer')->where('id', $id)->update([
|
||||
'status' => $status,
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
Db::table('ma_merchant_app')->where('merchant_id', $id)->update([
|
||||
Db::table('ma_pay_app')->where('mer_id', $id)->update([
|
||||
'status' => $status,
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
@@ -733,6 +707,8 @@ class MerchantController extends BaseController
|
||||
'merchant_id' => (int)$request->get('merchant_id', 0),
|
||||
'status' => (string)$request->get('status', ''),
|
||||
'keyword' => trim((string)$request->get('keyword', '')),
|
||||
'email' => trim((string)$request->get('email', '')),
|
||||
'balance' => trim((string)$request->get('balance', '')),
|
||||
'created_from' => trim((string)$request->get('created_from', '')),
|
||||
'created_to' => trim((string)$request->get('created_to', '')),
|
||||
];
|
||||
@@ -749,9 +725,16 @@ class MerchantController extends BaseController
|
||||
if (!empty($filters['keyword'])) {
|
||||
$query->where(function ($builder) use ($filters) {
|
||||
$builder->where('m.merchant_no', 'like', '%' . $filters['keyword'] . '%')
|
||||
->orWhere('m.merchant_name', 'like', '%' . $filters['keyword'] . '%');
|
||||
->orWhere('m.merchant_name', 'like', '%' . $filters['keyword'] . '%')
|
||||
->orWhere('m.email', 'like', '%' . $filters['keyword'] . '%');
|
||||
});
|
||||
}
|
||||
if (!empty($filters['email'])) {
|
||||
$query->where('m.email', 'like', '%' . $filters['email'] . '%');
|
||||
}
|
||||
if (isset($filters['balance']) && $filters['balance'] !== '') {
|
||||
$query->where('m.balance', (string)$filters['balance']);
|
||||
}
|
||||
}
|
||||
|
||||
private function getConfigEntries(string $configKey): array
|
||||
@@ -863,6 +846,31 @@ class MerchantController extends BaseController
|
||||
return $map;
|
||||
}
|
||||
|
||||
private function normalizeMerchantRow(array $merchant): array
|
||||
{
|
||||
$merchant['merchant_no'] = trim((string)($merchant['merchant_no'] ?? ''));
|
||||
$merchant['merchant_name'] = trim((string)($merchant['merchant_name'] ?? ''));
|
||||
$merchant['balance'] = (string)($merchant['balance'] ?? '0.00');
|
||||
$merchant['email'] = trim((string)($merchant['email'] ?? ''));
|
||||
$merchant['remark'] = trim((string)($merchant['remark'] ?? ''));
|
||||
$merchant['status'] = (int)($merchant['status'] ?? 1);
|
||||
$merchant['created_at'] = (string)($merchant['created_at'] ?? '');
|
||||
$merchant['updated_at'] = (string)($merchant['updated_at'] ?? '');
|
||||
return $merchant;
|
||||
}
|
||||
|
||||
private function buildMerchantProfile(array $merchant): array
|
||||
{
|
||||
return [
|
||||
'merchant_no' => trim((string)($merchant['merchant_no'] ?? '')),
|
||||
'merchant_name' => trim((string)($merchant['merchant_name'] ?? '')),
|
||||
'balance' => (string)($merchant['balance'] ?? '0.00'),
|
||||
'email' => trim((string)($merchant['email'] ?? '')),
|
||||
'status' => (int)($merchant['status'] ?? 1),
|
||||
'remark' => trim((string)($merchant['remark'] ?? '')),
|
||||
];
|
||||
}
|
||||
|
||||
private function getConfigObject(string $configKey): array
|
||||
{
|
||||
$raw = $this->systemConfigService->getValue($configKey, '{}');
|
||||
|
||||
@@ -54,8 +54,8 @@ class PayMethodController extends BaseController
|
||||
|
||||
if ($id > 0) {
|
||||
$this->methodRepository->updateById($id, [
|
||||
'method_code' => $code,
|
||||
'method_name' => $name,
|
||||
'type' => $code,
|
||||
'name' => $name,
|
||||
'icon' => $icon,
|
||||
'sort' => $sort,
|
||||
'status' => $status,
|
||||
@@ -66,8 +66,8 @@ class PayMethodController extends BaseController
|
||||
return $this->fail('支付方式编码已存在', 400);
|
||||
}
|
||||
$this->methodRepository->create([
|
||||
'method_code' => $code,
|
||||
'method_name' => $name,
|
||||
'type' => $code,
|
||||
'name' => $name,
|
||||
'icon' => $icon,
|
||||
'sort' => $sort,
|
||||
'status' => $status,
|
||||
|
||||
@@ -9,19 +9,25 @@ use app\common\base\BaseModel;
|
||||
*/
|
||||
class Merchant extends BaseModel
|
||||
{
|
||||
protected $table = 'ma_merchant';
|
||||
protected $table = 'ma_mer';
|
||||
|
||||
protected $fillable = [
|
||||
'merchant_no',
|
||||
'merchant_name',
|
||||
'balance',
|
||||
'email',
|
||||
'funds_mode',
|
||||
'status',
|
||||
'remark',
|
||||
'extra',
|
||||
];
|
||||
|
||||
public $timestamps = true;
|
||||
|
||||
protected $casts = [
|
||||
'balance' => 'decimal:2',
|
||||
'status' => 'integer',
|
||||
'extra' => 'array',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -9,22 +9,65 @@ use app\common\base\BaseModel;
|
||||
*/
|
||||
class MerchantApp extends BaseModel
|
||||
{
|
||||
protected $table = 'ma_merchant_app';
|
||||
protected $table = 'ma_pay_app';
|
||||
|
||||
protected $fillable = [
|
||||
'merchant_id',
|
||||
'mer_id',
|
||||
'api_type',
|
||||
'app_id',
|
||||
'app_code',
|
||||
'app_secret',
|
||||
'app_name',
|
||||
'status',
|
||||
'remark',
|
||||
'package_code',
|
||||
'notify_url',
|
||||
'return_url',
|
||||
'callback_mode',
|
||||
'sign_type',
|
||||
'order_expire_minutes',
|
||||
'callback_retry_limit',
|
||||
'ip_whitelist',
|
||||
'amount_min',
|
||||
'amount_max',
|
||||
'daily_limit',
|
||||
'notify_enabled',
|
||||
'extra',
|
||||
];
|
||||
|
||||
public $timestamps = true;
|
||||
|
||||
|
||||
protected $appends = ['merchant_id', 'app_id'];
|
||||
|
||||
protected $casts = [
|
||||
'merchant_id' => 'integer',
|
||||
'mer_id' => 'integer',
|
||||
'order_expire_minutes' => 'integer',
|
||||
'callback_retry_limit' => 'integer',
|
||||
'amount_min' => 'decimal:2',
|
||||
'amount_max' => 'decimal:2',
|
||||
'daily_limit' => 'decimal:2',
|
||||
'notify_enabled' => 'integer',
|
||||
'status' => 'integer',
|
||||
'extra' => 'array',
|
||||
];
|
||||
|
||||
public function getMerchantIdAttribute()
|
||||
{
|
||||
return $this->attributes['mer_id'] ?? null;
|
||||
}
|
||||
|
||||
public function setMerchantIdAttribute($value): void
|
||||
{
|
||||
$this->attributes['mer_id'] = (int)$value;
|
||||
}
|
||||
|
||||
public function getAppIdAttribute()
|
||||
{
|
||||
return $this->attributes['app_code'] ?? null;
|
||||
}
|
||||
|
||||
public function setAppIdAttribute($value): void
|
||||
{
|
||||
$this->attributes['app_code'] = (string)$value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
51
app/models/MerchantUser.php
Normal file
51
app/models/MerchantUser.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace app\models;
|
||||
|
||||
use app\common\base\BaseModel;
|
||||
|
||||
/**
|
||||
* 商户后台用户模型
|
||||
*/
|
||||
class MerchantUser extends BaseModel
|
||||
{
|
||||
protected $table = 'ma_mer_user';
|
||||
|
||||
protected $fillable = [
|
||||
'mer_id',
|
||||
'username',
|
||||
'password',
|
||||
'nick_name',
|
||||
'avatar',
|
||||
'mobile',
|
||||
'email',
|
||||
'role_code',
|
||||
'is_owner',
|
||||
'status',
|
||||
'login_ip',
|
||||
'login_at',
|
||||
];
|
||||
|
||||
public $timestamps = true;
|
||||
|
||||
protected $appends = ['merchant_id'];
|
||||
|
||||
protected $casts = [
|
||||
'mer_id' => 'integer',
|
||||
'is_owner' => 'integer',
|
||||
'status' => 'integer',
|
||||
'login_at' => 'datetime',
|
||||
];
|
||||
|
||||
protected $hidden = ['password'];
|
||||
|
||||
public function getMerchantIdAttribute()
|
||||
{
|
||||
return $this->attributes['mer_id'] ?? null;
|
||||
}
|
||||
|
||||
public function setMerchantIdAttribute($value): void
|
||||
{
|
||||
$this->attributes['mer_id'] = (int)$value;
|
||||
}
|
||||
}
|
||||
@@ -14,13 +14,13 @@ class PaymentChannel extends BaseModel
|
||||
protected $table = 'ma_pay_channel';
|
||||
|
||||
protected $fillable = [
|
||||
'merchant_id',
|
||||
'merchant_app_id',
|
||||
'mer_id',
|
||||
'app_id',
|
||||
'chan_code',
|
||||
'chan_name',
|
||||
'plugin_code',
|
||||
'method_id',
|
||||
'config_json',
|
||||
'pay_type_id',
|
||||
'config',
|
||||
'split_ratio',
|
||||
'chan_cost',
|
||||
'chan_mode',
|
||||
@@ -34,13 +34,16 @@ class PaymentChannel extends BaseModel
|
||||
|
||||
public $timestamps = true;
|
||||
|
||||
protected $appends = ['merchant_id', 'merchant_app_id', 'method_id', 'config_json'];
|
||||
|
||||
protected $casts = [
|
||||
'merchant_id' => 'integer',
|
||||
'merchant_app_id' => 'integer',
|
||||
'method_id' => 'integer',
|
||||
'config_json' => 'array',
|
||||
'mer_id' => 'integer',
|
||||
'app_id' => 'integer',
|
||||
'pay_type_id' => 'integer',
|
||||
'config' => 'array',
|
||||
'split_ratio' => 'decimal:2',
|
||||
'chan_cost' => 'decimal:2',
|
||||
'chan_mode' => 'integer',
|
||||
'daily_limit' => 'decimal:2',
|
||||
'daily_cnt' => 'integer',
|
||||
'min_amount' => 'decimal:2',
|
||||
@@ -51,7 +54,7 @@ class PaymentChannel extends BaseModel
|
||||
|
||||
public function getConfigArray(): array
|
||||
{
|
||||
return $this->config_json ?? [];
|
||||
return $this->config ?? [];
|
||||
}
|
||||
|
||||
public function getEnabledProducts(): array
|
||||
@@ -59,4 +62,44 @@ class PaymentChannel extends BaseModel
|
||||
$config = $this->getConfigArray();
|
||||
return $config['enabled_products'] ?? [];
|
||||
}
|
||||
|
||||
public function getMerchantIdAttribute()
|
||||
{
|
||||
return $this->attributes['mer_id'] ?? null;
|
||||
}
|
||||
|
||||
public function setMerchantIdAttribute($value): void
|
||||
{
|
||||
$this->attributes['mer_id'] = (int)$value;
|
||||
}
|
||||
|
||||
public function getMerchantAppIdAttribute()
|
||||
{
|
||||
return $this->attributes['app_id'] ?? null;
|
||||
}
|
||||
|
||||
public function setMerchantAppIdAttribute($value): void
|
||||
{
|
||||
$this->attributes['app_id'] = (int)$value;
|
||||
}
|
||||
|
||||
public function getMethodIdAttribute()
|
||||
{
|
||||
return $this->attributes['pay_type_id'] ?? null;
|
||||
}
|
||||
|
||||
public function setMethodIdAttribute($value): void
|
||||
{
|
||||
$this->attributes['pay_type_id'] = (int)$value;
|
||||
}
|
||||
|
||||
public function getConfigJsonAttribute()
|
||||
{
|
||||
return $this->attributes['config'] ?? [];
|
||||
}
|
||||
|
||||
public function setConfigJsonAttribute($value): void
|
||||
{
|
||||
$this->attributes['config'] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ use app\common\base\BaseModel;
|
||||
*/
|
||||
class PaymentMethod extends BaseModel
|
||||
{
|
||||
protected $table = 'ma_pay_method';
|
||||
protected $table = 'ma_pay_type';
|
||||
|
||||
protected $fillable = [
|
||||
'method_code',
|
||||
'method_name',
|
||||
'type',
|
||||
'name',
|
||||
'icon',
|
||||
'sort',
|
||||
'status',
|
||||
@@ -23,8 +23,30 @@ class PaymentMethod extends BaseModel
|
||||
|
||||
public $timestamps = true;
|
||||
|
||||
protected $appends = ['method_code', 'method_name'];
|
||||
|
||||
protected $casts = [
|
||||
'sort' => 'integer',
|
||||
'status' => 'integer',
|
||||
];
|
||||
|
||||
public function getMethodCodeAttribute()
|
||||
{
|
||||
return $this->attributes['type'] ?? null;
|
||||
}
|
||||
|
||||
public function setMethodCodeAttribute($value): void
|
||||
{
|
||||
$this->attributes['type'] = (string)$value;
|
||||
}
|
||||
|
||||
public function getMethodNameAttribute()
|
||||
{
|
||||
return $this->attributes['name'] ?? null;
|
||||
}
|
||||
|
||||
public function setMethodNameAttribute($value): void
|
||||
{
|
||||
$this->attributes['name'] = (string)$value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class MerchantAppRepository extends BaseRepository
|
||||
public function findByAppId(string $appId): ?MerchantApp
|
||||
{
|
||||
return $this->model->newQuery()
|
||||
->where('app_id', $appId)
|
||||
->where('app_code', $appId)
|
||||
->where('status', 1)
|
||||
->first();
|
||||
}
|
||||
@@ -32,19 +32,30 @@ class MerchantAppRepository extends BaseRepository
|
||||
public function findByMerchantAndApp(int $merchantId, int $appId): ?MerchantApp
|
||||
{
|
||||
return $this->model->newQuery()
|
||||
->where('merchant_id', $merchantId)
|
||||
->where('mer_id', $merchantId)
|
||||
->where('id', $appId)
|
||||
->where('status', 1)
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据商户ID和应用ID(app_id)查询
|
||||
*/
|
||||
public function findByMerchantAndAppId(int $merchantId, string $appId): ?MerchantApp
|
||||
{
|
||||
return $this->model->newQuery()
|
||||
->where('mer_id', $merchantId)
|
||||
->where('app_code', $appId)
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台按 app_id 查询(不过滤状态)
|
||||
*/
|
||||
public function findAnyByAppId(string $appId): ?MerchantApp
|
||||
{
|
||||
return $this->model->newQuery()
|
||||
->where('app_id', $appId)
|
||||
->where('app_code', $appId)
|
||||
->first();
|
||||
}
|
||||
|
||||
@@ -56,13 +67,13 @@ class MerchantAppRepository extends BaseRepository
|
||||
$query = $this->model->newQuery();
|
||||
|
||||
if (!empty($filters['merchant_id'])) {
|
||||
$query->where('merchant_id', (int)$filters['merchant_id']);
|
||||
$query->where('mer_id', (int)$filters['merchant_id']);
|
||||
}
|
||||
if (($filters['status'] ?? '') !== '' && $filters['status'] !== null) {
|
||||
$query->where('status', (int)$filters['status']);
|
||||
}
|
||||
if (!empty($filters['app_id'])) {
|
||||
$query->where('app_id', 'like', '%' . $filters['app_id'] . '%');
|
||||
$query->where('app_code', 'like', '%' . $filters['app_id'] . '%');
|
||||
}
|
||||
if (!empty($filters['app_name'])) {
|
||||
$query->where('app_name', 'like', '%' . $filters['app_name'] . '%');
|
||||
@@ -70,6 +81,15 @@ class MerchantAppRepository extends BaseRepository
|
||||
if (!empty($filters['api_type'])) {
|
||||
$query->where('api_type', (string)$filters['api_type']);
|
||||
}
|
||||
if (!empty($filters['package_code'])) {
|
||||
$query->where('package_code', (string)$filters['package_code']);
|
||||
}
|
||||
if (($filters['notify_enabled'] ?? '') !== '' && $filters['notify_enabled'] !== null) {
|
||||
$query->where('notify_enabled', (int)$filters['notify_enabled']);
|
||||
}
|
||||
if (!empty($filters['callback_mode'])) {
|
||||
$query->where('callback_mode', (string)$filters['callback_mode']);
|
||||
}
|
||||
|
||||
$query->orderByDesc('id');
|
||||
|
||||
|
||||
@@ -41,6 +41,12 @@ class MerchantRepository extends BaseRepository
|
||||
if (!empty($filters['merchant_name'])) {
|
||||
$query->where('merchant_name', 'like', '%' . $filters['merchant_name'] . '%');
|
||||
}
|
||||
if (!empty($filters['email'])) {
|
||||
$query->where('email', 'like', '%' . $filters['email'] . '%');
|
||||
}
|
||||
if (isset($filters['balance']) && $filters['balance'] !== '') {
|
||||
$query->where('balance', (string)$filters['balance']);
|
||||
}
|
||||
|
||||
$query->orderByDesc('id');
|
||||
|
||||
|
||||
@@ -15,9 +15,9 @@ class PaymentChannelRepository extends BaseRepository
|
||||
public function findAvailableChannel(int $merchantId, int $merchantAppId, int $methodId): ?PaymentChannel
|
||||
{
|
||||
return $this->model->newQuery()
|
||||
->where('merchant_id', $merchantId)
|
||||
->where('merchant_app_id', $merchantAppId)
|
||||
->where('method_id', $methodId)
|
||||
->where('mer_id', $merchantId)
|
||||
->where('app_id', $merchantAppId)
|
||||
->where('pay_type_id', $methodId)
|
||||
->where('status', 1)
|
||||
->orderBy('sort', 'asc')
|
||||
->first();
|
||||
@@ -51,13 +51,13 @@ class PaymentChannelRepository extends BaseRepository
|
||||
$query = $this->model->newQuery();
|
||||
|
||||
if (!empty($filters['merchant_id'])) {
|
||||
$query->where('merchant_id', (int)$filters['merchant_id']);
|
||||
$query->where('mer_id', (int)$filters['merchant_id']);
|
||||
}
|
||||
if (!empty($filters['merchant_app_id'])) {
|
||||
$query->where('merchant_app_id', (int)$filters['merchant_app_id']);
|
||||
$query->where('app_id', (int)$filters['merchant_app_id']);
|
||||
}
|
||||
if (!empty($filters['method_id'])) {
|
||||
$query->where('method_id', (int)$filters['method_id']);
|
||||
$query->where('pay_type_id', (int)$filters['method_id']);
|
||||
}
|
||||
if (($filters['status'] ?? '') !== '' && $filters['status'] !== null) {
|
||||
$query->where('status', (int)$filters['status']);
|
||||
|
||||
@@ -27,7 +27,7 @@ class PaymentMethodRepository extends BaseRepository
|
||||
public function findByCode(string $methodCode): ?PaymentMethod
|
||||
{
|
||||
return $this->model->newQuery()
|
||||
->where('method_code', $methodCode)
|
||||
->where('type', $methodCode)
|
||||
->where('status', 1)
|
||||
->first();
|
||||
}
|
||||
@@ -38,7 +38,7 @@ class PaymentMethodRepository extends BaseRepository
|
||||
public function findAnyByCode(string $methodCode): ?PaymentMethod
|
||||
{
|
||||
return $this->model->newQuery()
|
||||
->where('method_code', $methodCode)
|
||||
->where('type', $methodCode)
|
||||
->first();
|
||||
}
|
||||
|
||||
@@ -53,10 +53,10 @@ class PaymentMethodRepository extends BaseRepository
|
||||
$query->where('status', (int)$filters['status']);
|
||||
}
|
||||
if (!empty($filters['method_code'])) {
|
||||
$query->where('method_code', 'like', '%' . $filters['method_code'] . '%');
|
||||
$query->where('type', 'like', '%' . $filters['method_code'] . '%');
|
||||
}
|
||||
if (!empty($filters['method_name'])) {
|
||||
$query->where('method_name', 'like', '%' . $filters['method_name'] . '%');
|
||||
$query->where('name', 'like', '%' . $filters['method_name'] . '%');
|
||||
}
|
||||
|
||||
$query->orderBy('sort', 'asc')->orderByDesc('id');
|
||||
|
||||
169
database/20260320_align_current_schema.sql
Normal file
169
database/20260320_align_current_schema.sql
Normal file
@@ -0,0 +1,169 @@
|
||||
-- Current schema alignment for the updated merchant / merchant-app model.
|
||||
-- Target DB: MySQL 5.7+
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- =========================================================
|
||||
-- 1. Expand ma_mer for admin + merchant backend scenarios
|
||||
-- =========================================================
|
||||
ALTER TABLE `ma_mer`
|
||||
ADD COLUMN `merchant_short_name` varchar(60) NOT NULL DEFAULT '' COMMENT '商户简称' AFTER `merchant_name`,
|
||||
ADD COLUMN `merchant_type` varchar(20) NOT NULL DEFAULT 'company' COMMENT '商户类型:company/individual/other' AFTER `merchant_short_name`,
|
||||
ADD COLUMN `group_code` varchar(32) NOT NULL DEFAULT '' COMMENT '商户分组编码' AFTER `merchant_type`,
|
||||
ADD COLUMN `legal_name` varchar(100) NOT NULL DEFAULT '' COMMENT '法人姓名' AFTER `funds_mode`,
|
||||
ADD COLUMN `contact_name` varchar(50) NOT NULL DEFAULT '' COMMENT '联系人姓名' AFTER `legal_name`,
|
||||
ADD COLUMN `contact_phone` varchar(20) NOT NULL DEFAULT '' COMMENT '联系人手机号' AFTER `contact_name`,
|
||||
ADD COLUMN `contact_email` varchar(100) NOT NULL DEFAULT '' COMMENT '联系人邮箱' AFTER `contact_phone`,
|
||||
ADD COLUMN `website` varchar(255) NOT NULL DEFAULT '' COMMENT '商户官网' AFTER `contact_email`,
|
||||
ADD COLUMN `province` varchar(50) NOT NULL DEFAULT '' COMMENT '省份' AFTER `website`,
|
||||
ADD COLUMN `city` varchar(50) NOT NULL DEFAULT '' COMMENT '城市' AFTER `province`,
|
||||
ADD COLUMN `address` varchar(255) NOT NULL DEFAULT '' COMMENT '详细地址' AFTER `city`,
|
||||
ADD COLUMN `callback_domain` varchar(255) NOT NULL DEFAULT '' COMMENT '回调域名' AFTER `address`,
|
||||
ADD COLUMN `callback_ip_whitelist` text COMMENT '回调IP白名单' AFTER `callback_domain`,
|
||||
ADD COLUMN `risk_level` varchar(20) NOT NULL DEFAULT 'standard' COMMENT '风控等级:low/standard/high' AFTER `callback_ip_whitelist`,
|
||||
ADD COLUMN `settlement_mode` varchar(20) NOT NULL DEFAULT 'auto' COMMENT '结算方式:auto/manual' AFTER `risk_level`,
|
||||
ADD COLUMN `settlement_cycle` varchar(20) NOT NULL DEFAULT 't1' COMMENT '结算周期:d0/t1/manual' AFTER `settlement_mode`,
|
||||
ADD COLUMN `settlement_account_name` varchar(100) NOT NULL DEFAULT '' COMMENT '结算账户名' AFTER `settlement_cycle`,
|
||||
ADD COLUMN `settlement_account_no` varchar(100) NOT NULL DEFAULT '' COMMENT '结算账户号' AFTER `settlement_account_name`,
|
||||
ADD COLUMN `settlement_bank_name` varchar(100) NOT NULL DEFAULT '' COMMENT '结算银行名称' AFTER `settlement_account_no`,
|
||||
ADD COLUMN `settlement_bank_branch` varchar(100) NOT NULL DEFAULT '' COMMENT '结算支行名称' AFTER `settlement_bank_name`,
|
||||
ADD COLUMN `single_limit` decimal(12,2) NOT NULL DEFAULT 0.00 COMMENT '单笔限额(元)' AFTER `settlement_bank_branch`,
|
||||
ADD COLUMN `daily_limit` decimal(12,2) NOT NULL DEFAULT 0.00 COMMENT '日限额(元)' AFTER `single_limit`,
|
||||
ADD COLUMN `remark` varchar(500) NOT NULL DEFAULT '' COMMENT '备注' AFTER `daily_limit`,
|
||||
ADD COLUMN `extra` json DEFAULT NULL COMMENT '扩展字段(JSON)' AFTER `remark`;
|
||||
|
||||
ALTER TABLE `ma_mer`
|
||||
ADD KEY `idx_group_code` (`group_code`),
|
||||
ADD KEY `idx_contact_phone` (`contact_phone`),
|
||||
ADD KEY `idx_status` (`status`);
|
||||
|
||||
-- =========================================================
|
||||
-- 2. Expand ma_pay_app for merchant app backend settings
|
||||
-- =========================================================
|
||||
ALTER TABLE `ma_pay_app`
|
||||
ADD COLUMN `package_code` varchar(32) NOT NULL DEFAULT '' COMMENT '商户套餐编码' AFTER `app_name`,
|
||||
ADD COLUMN `notify_url` varchar(255) NOT NULL DEFAULT '' COMMENT '异步通知地址' AFTER `package_code`,
|
||||
ADD COLUMN `return_url` varchar(255) NOT NULL DEFAULT '' COMMENT '同步跳转地址' AFTER `notify_url`,
|
||||
ADD COLUMN `callback_mode` varchar(20) NOT NULL DEFAULT 'server' COMMENT '回调模式:server/server+page/manual' AFTER `return_url`,
|
||||
ADD COLUMN `sign_type` varchar(20) NOT NULL DEFAULT 'md5' COMMENT '签名方式' AFTER `callback_mode`,
|
||||
ADD COLUMN `order_expire_minutes` int(11) NOT NULL DEFAULT 30 COMMENT '订单超时时间(分钟)' AFTER `sign_type`,
|
||||
ADD COLUMN `callback_retry_limit` int(11) NOT NULL DEFAULT 6 COMMENT '回调重试次数' AFTER `order_expire_minutes`,
|
||||
ADD COLUMN `ip_whitelist` text COMMENT 'IP白名单' AFTER `callback_retry_limit`,
|
||||
ADD COLUMN `amount_min` decimal(12,2) NOT NULL DEFAULT 0.00 COMMENT '单笔最小金额' AFTER `ip_whitelist`,
|
||||
ADD COLUMN `amount_max` decimal(12,2) NOT NULL DEFAULT 0.00 COMMENT '单笔最大金额' AFTER `amount_min`,
|
||||
ADD COLUMN `daily_limit` decimal(12,2) NOT NULL DEFAULT 0.00 COMMENT '日限额' AFTER `amount_max`,
|
||||
ADD COLUMN `notify_enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否开启通知:0-否,1-是' AFTER `daily_limit`,
|
||||
ADD COLUMN `remark` varchar(500) NOT NULL DEFAULT '' COMMENT '备注' AFTER `notify_enabled`,
|
||||
ADD COLUMN `extra` json DEFAULT NULL COMMENT '扩展字段(JSON)' AFTER `remark`;
|
||||
|
||||
ALTER TABLE `ma_pay_app`
|
||||
ADD KEY `idx_api_type` (`api_type`),
|
||||
ADD KEY `idx_status` (`status`);
|
||||
|
||||
-- =========================================================
|
||||
-- 3. Merchant backend user table
|
||||
-- =========================================================
|
||||
CREATE TABLE IF NOT EXISTS `ma_mer_user` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`mer_id` bigint unsigned NOT NULL DEFAULT 0 COMMENT '商户ID',
|
||||
`username` varchar(50) NOT NULL DEFAULT '' COMMENT '登录账号',
|
||||
`password` varchar(255) DEFAULT NULL COMMENT '登录密码hash',
|
||||
`nick_name` varchar(50) NOT NULL DEFAULT '' COMMENT '昵称',
|
||||
`avatar` varchar(255) NOT NULL DEFAULT '' COMMENT '头像地址',
|
||||
`mobile` varchar(20) NOT NULL DEFAULT '' COMMENT '手机号',
|
||||
`email` varchar(100) NOT NULL DEFAULT '' COMMENT '邮箱',
|
||||
`role_code` varchar(32) NOT NULL DEFAULT 'owner' COMMENT '角色编码',
|
||||
`is_owner` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否商户主账号:0-否,1-是',
|
||||
`status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态:0-禁用,1-启用',
|
||||
`login_ip` varchar(45) NOT NULL DEFAULT '' COMMENT '最后登录IP',
|
||||
`login_at` datetime DEFAULT NULL COMMENT '最后登录时间',
|
||||
`created_at` datetime DEFAULT NULL COMMENT '创建时间',
|
||||
`updated_at` datetime DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_username` (`username`),
|
||||
KEY `idx_mer_id` (`mer_id`),
|
||||
KEY `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商户后台用户表';
|
||||
|
||||
-- =========================================================
|
||||
-- 4. Compatibility views for legacy code paths
|
||||
-- =========================================================
|
||||
DROP VIEW IF EXISTS `ma_merchant`;
|
||||
CREATE VIEW `ma_merchant` AS
|
||||
SELECT
|
||||
`id`,
|
||||
`merchant_no`,
|
||||
`merchant_name`,
|
||||
`merchant_short_name`,
|
||||
`merchant_type`,
|
||||
`group_code`,
|
||||
`funds_mode`,
|
||||
`legal_name`,
|
||||
`contact_name`,
|
||||
`contact_phone`,
|
||||
`contact_email`,
|
||||
`website`,
|
||||
`province`,
|
||||
`city`,
|
||||
`address`,
|
||||
`callback_domain`,
|
||||
`callback_ip_whitelist`,
|
||||
`risk_level`,
|
||||
`settlement_mode`,
|
||||
`settlement_cycle`,
|
||||
`settlement_account_name`,
|
||||
`settlement_account_no`,
|
||||
`settlement_bank_name`,
|
||||
`settlement_bank_branch`,
|
||||
`single_limit`,
|
||||
`daily_limit`,
|
||||
`status`,
|
||||
`remark`,
|
||||
`extra`,
|
||||
`created_at`,
|
||||
`updated_at`
|
||||
FROM `ma_mer`;
|
||||
|
||||
DROP VIEW IF EXISTS `ma_merchant_app`;
|
||||
CREATE VIEW `ma_merchant_app` AS
|
||||
SELECT
|
||||
`id`,
|
||||
`mer_id` AS `merchant_id`,
|
||||
`api_type`,
|
||||
`app_code` AS `app_id`,
|
||||
`app_secret`,
|
||||
`app_name`,
|
||||
`package_code`,
|
||||
`notify_url`,
|
||||
`return_url`,
|
||||
`callback_mode`,
|
||||
`sign_type`,
|
||||
`order_expire_minutes`,
|
||||
`callback_retry_limit`,
|
||||
`ip_whitelist`,
|
||||
`amount_min`,
|
||||
`amount_max`,
|
||||
`daily_limit`,
|
||||
`notify_enabled`,
|
||||
`status`,
|
||||
`remark`,
|
||||
`extra`,
|
||||
`created_at`,
|
||||
`updated_at`
|
||||
FROM `ma_pay_app`;
|
||||
|
||||
DROP VIEW IF EXISTS `ma_pay_method`;
|
||||
CREATE VIEW `ma_pay_method` AS
|
||||
SELECT
|
||||
`id`,
|
||||
`type` AS `method_code`,
|
||||
`name` AS `method_name`,
|
||||
`icon`,
|
||||
`sort`,
|
||||
`status`,
|
||||
`created_at`,
|
||||
`updated_at`
|
||||
FROM `ma_pay_type`;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
@@ -78,13 +78,13 @@ ON DUPLICATE KEY UPDATE
|
||||
|
||||
-- 7) 支付通道(为测试商户 M001 / 应用 1001 初始化拉卡拉通道)
|
||||
INSERT INTO `ma_pay_channel` (
|
||||
`merchant_id`,
|
||||
`merchant_app_id`,
|
||||
`mer_id`,
|
||||
`app_id`,
|
||||
`chan_code`,
|
||||
`chan_name`,
|
||||
`plugin_code`,
|
||||
`method_id`,
|
||||
`config_json`,
|
||||
`pay_type_id`,
|
||||
`config`,
|
||||
`split_ratio`,
|
||||
`chan_cost`,
|
||||
`chan_mode`,
|
||||
@@ -98,16 +98,16 @@ INSERT INTO `ma_pay_channel` (
|
||||
`updated_at`
|
||||
)
|
||||
SELECT
|
||||
m.id AS merchant_id,
|
||||
app.id AS merchant_app_id,
|
||||
m.id AS mer_id,
|
||||
app.id AS app_id,
|
||||
'lakala_alipay' AS chan_code,
|
||||
'拉卡拉-支付宝' AS chan_name,
|
||||
'lakala' AS plugin_code,
|
||||
pm.id AS method_id,
|
||||
JSON_OBJECT('notify_url', 'https://example.com/notify') AS config_json,
|
||||
pm.id AS pay_type_id,
|
||||
JSON_OBJECT('notify_url', 'https://example.com/notify') AS config,
|
||||
100.00 AS split_ratio,
|
||||
0.00 AS chan_cost,
|
||||
'wallet' AS chan_mode,
|
||||
0 AS chan_mode,
|
||||
0.00 AS daily_limit,
|
||||
0 AS daily_cnt,
|
||||
0.01 AS min_amount,
|
||||
@@ -122,8 +122,8 @@ JOIN `ma_pay_method` pm ON pm.method_code = 'alipay'
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`chan_name` = VALUES(`chan_name`),
|
||||
`plugin_code` = VALUES(`plugin_code`),
|
||||
`method_id` = VALUES(`method_id`),
|
||||
`config_json` = VALUES(`config_json`),
|
||||
`pay_type_id` = VALUES(`pay_type_id`),
|
||||
`config` = VALUES(`config`),
|
||||
`split_ratio` = VALUES(`split_ratio`),
|
||||
`chan_cost` = VALUES(`chan_cost`),
|
||||
`chan_mode` = VALUES(`chan_mode`),
|
||||
@@ -136,13 +136,13 @@ ON DUPLICATE KEY UPDATE
|
||||
`updated_at` = NOW();
|
||||
|
||||
INSERT INTO `ma_pay_channel` (
|
||||
`merchant_id`,
|
||||
`merchant_app_id`,
|
||||
`mer_id`,
|
||||
`app_id`,
|
||||
`chan_code`,
|
||||
`chan_name`,
|
||||
`plugin_code`,
|
||||
`method_id`,
|
||||
`config_json`,
|
||||
`pay_type_id`,
|
||||
`config`,
|
||||
`split_ratio`,
|
||||
`chan_cost`,
|
||||
`chan_mode`,
|
||||
@@ -156,16 +156,16 @@ INSERT INTO `ma_pay_channel` (
|
||||
`updated_at`
|
||||
)
|
||||
SELECT
|
||||
m.id AS merchant_id,
|
||||
app.id AS merchant_app_id,
|
||||
m.id AS mer_id,
|
||||
app.id AS app_id,
|
||||
'lakala_wechat' AS chan_code,
|
||||
'拉卡拉-微信支付' AS chan_name,
|
||||
'lakala' AS plugin_code,
|
||||
pm.id AS method_id,
|
||||
JSON_OBJECT('notify_url', 'https://example.com/notify') AS config_json,
|
||||
pm.id AS pay_type_id,
|
||||
JSON_OBJECT('notify_url', 'https://example.com/notify') AS config,
|
||||
100.00 AS split_ratio,
|
||||
0.00 AS chan_cost,
|
||||
'wallet' AS chan_mode,
|
||||
0 AS chan_mode,
|
||||
0.00 AS daily_limit,
|
||||
0 AS daily_cnt,
|
||||
0.01 AS min_amount,
|
||||
@@ -180,8 +180,8 @@ JOIN `ma_pay_method` pm ON pm.method_code = 'wechat'
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`chan_name` = VALUES(`chan_name`),
|
||||
`plugin_code` = VALUES(`plugin_code`),
|
||||
`method_id` = VALUES(`method_id`),
|
||||
`config_json` = VALUES(`config_json`),
|
||||
`pay_type_id` = VALUES(`pay_type_id`),
|
||||
`config` = VALUES(`config`),
|
||||
`split_ratio` = VALUES(`split_ratio`),
|
||||
`chan_cost` = VALUES(`chan_cost`),
|
||||
`chan_mode` = VALUES(`chan_mode`),
|
||||
@@ -191,4 +191,4 @@ ON DUPLICATE KEY UPDATE
|
||||
`max_amount` = VALUES(`max_amount`),
|
||||
`status` = VALUES(`status`),
|
||||
`sort` = VALUES(`sort`),
|
||||
`updated_at` = NOW();
|
||||
`updated_at` = NOW();
|
||||
|
||||
Reference in New Issue
Block a user