Deploy: 2026-05-22 03:37:23

This commit is contained in:
Hamza-Ayed
2026-05-22 03:37:23 +03:00
parent 479aedcbcf
commit 8448f13dfc
5 changed files with 761 additions and 2 deletions

View 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());
}
}
}