Deploy: 2026-05-22 03:37:23
This commit is contained in:
161
backend/app/Models/SallaMerchant.php
Normal file
161
backend/app/Models/SallaMerchant.php
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Core\Database;
|
||||
|
||||
/**
|
||||
* SallaMerchant Model
|
||||
* Handles database representation of Salla e-commerce store links per company.
|
||||
*/
|
||||
class SallaMerchant extends BaseModel
|
||||
{
|
||||
protected static string $table = 'salla_merchants';
|
||||
|
||||
/**
|
||||
* Find merchant info by company ID
|
||||
*/
|
||||
public static function findByCompany(int $companyId): ?array
|
||||
{
|
||||
self::ensureTableExists();
|
||||
return Database::selectOne(
|
||||
"SELECT * FROM " . static::$table . " WHERE company_id = ? LIMIT 1",
|
||||
[$companyId]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find merchant info by Salla merchant ID
|
||||
*/
|
||||
public static function findByMerchantId(string $merchantId): ?array
|
||||
{
|
||||
self::ensureTableExists();
|
||||
return Database::selectOne(
|
||||
"SELECT * FROM " . static::$table . " WHERE merchant_id = ? LIMIT 1",
|
||||
[$merchantId]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save or update Salla merchant credentials
|
||||
*/
|
||||
public static function saveSecure(array $data): string
|
||||
{
|
||||
self::ensureTableExists();
|
||||
|
||||
$existing = self::findByCompany($data['company_id']);
|
||||
if ($existing) {
|
||||
self::update($existing['id'], $data);
|
||||
return $existing['id'];
|
||||
} else {
|
||||
return self::create($data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete credentials for a company
|
||||
*/
|
||||
public static function deleteByCompany(int $companyId): int
|
||||
{
|
||||
self::ensureTableExists();
|
||||
return Database::execute(
|
||||
"DELETE FROM " . static::$table . " WHERE company_id = ?",
|
||||
[$companyId]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or dynamically refresh the access token for a company
|
||||
*/
|
||||
public static function getOrRefreshAccessToken(int $companyId): ?string
|
||||
{
|
||||
$merchant = self::findByCompany($companyId);
|
||||
if (!$merchant) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if token expires_at is in the future (> 5 mins remaining)
|
||||
$expiresAt = strtotime($merchant['expires_at']);
|
||||
if ($expiresAt && ($expiresAt - time()) > 300) {
|
||||
return $merchant['access_token'];
|
||||
}
|
||||
|
||||
// Token expired or close to it, refresh
|
||||
$clientId = getenv('SALLA_CLIENT_ID') ?: '69ea789c-f611-4ea7-a3ee-7ead41420225';
|
||||
$clientSecret = getenv('SALLA_CLIENT_SECRET') ?: '';
|
||||
|
||||
$ch = curl_init('https://accounts.salla.sa/oauth2/token');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
|
||||
'client_id' => $clientId,
|
||||
'client_secret' => $clientSecret,
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $merchant['refresh_token']
|
||||
]));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/x-www-form-urlencoded'
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
|
||||
|
||||
$res = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($httpCode !== 200) {
|
||||
error_log("Failed to refresh Salla token for company $companyId. Response: $res");
|
||||
return null;
|
||||
}
|
||||
|
||||
$tokenData = json_decode($res, true);
|
||||
if (empty($tokenData['access_token'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$accessToken = $tokenData['access_token'];
|
||||
$refreshToken = $tokenData['refresh_token'] ?? $merchant['refresh_token'];
|
||||
$expiresIn = $tokenData['expires_in'] ?? 2592000;
|
||||
$newExpiresAt = date('Y-m-d H:i:s', time() + $expiresIn);
|
||||
|
||||
self::saveSecure([
|
||||
'company_id' => $companyId,
|
||||
'merchant_id' => $merchant['merchant_id'],
|
||||
'store_name' => $merchant['store_name'],
|
||||
'access_token' => $accessToken,
|
||||
'refresh_token' => $refreshToken,
|
||||
'expires_at' => $newExpiresAt
|
||||
]);
|
||||
|
||||
return $accessToken;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensure the salla_merchants table exists
|
||||
*/
|
||||
public static function ensureTableExists(): void
|
||||
{
|
||||
static $checked = false;
|
||||
if ($checked) return;
|
||||
|
||||
try {
|
||||
Database::execute("
|
||||
CREATE TABLE IF NOT EXISTS `salla_merchants` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`company_id` INT NOT NULL,
|
||||
`merchant_id` VARCHAR(100) NOT NULL UNIQUE,
|
||||
`store_name` VARCHAR(255) NULL,
|
||||
`access_token` TEXT NOT NULL,
|
||||
`refresh_token` TEXT NOT NULL,
|
||||
`expires_at` TIMESTAMP NULL DEFAULT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (`company_id`) REFERENCES `companies`(`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
");
|
||||
$checked = true;
|
||||
} catch (\Exception $e) {
|
||||
error_log("Failed to ensure salla_merchants table: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user