PluginProbe
ووسلام – همگام سازی ووکامرس و باسلام / 1.10.18
ووسلام – همگام سازی ووکامرس و باسلام v1.10.18
1.10.18 1.10.17 1.10.15 1.10.14 1.10.13 1.10.12 1.10.10 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.2 1.9.1 1.9.0 1.8.8 1.8.5 1.8.6 1.8.7 1.8.4 All 51 releases
sync-basalam / includes / Services / FinancialManagementService.php

FinancialManagementService.php in ووسلام – همگام سازی ووکامرس و باسلام 1.10.18, at includes/Services/FinancialManagementService.php

254 lines 7.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace SyncBasalam\Services;
4
5 use SyncBasalam\Admin\Settings\SettingsConfig;
6
7 defined('ABSPATH') || exit;
8
9 class FinancialManagementService
10 {
11 private const BALANCE_URL = 'https://accounting.basalam.com/financial/v1/client/transaction/balance';
12 private const BALANCE_SETTLEMENT_URL = 'https://accounting.basalam.com/financial/v1/client/balance-settlement';
13 private const BALANCE_SETTLEMENT_POST_URL = 'https://accounting.basalam.com/financial/v2/client/balance-settlement';
14 private const BANK_ACCOUNTS_URL = 'https://identity.basalam.com/v1/users/bank-accounts';
15 private const ACTIVE_STATUS_FILTER_TYPE = 2;
16 private const ACTIVE_STATUSES = [4, 6, 8, 9, 10];
17 private const DEFAULT_PER_PAGE = 20;
18
19 public function getDefaultPerPage(): int
20 {
21 return self::DEFAULT_PER_PAGE;
22 }
23
24 public function getBalanceUrl(): string
25 {
26 return self::BALANCE_URL;
27 }
28
29 public function getActiveSettlementsUrl(int $page = 1, int $perPage = self::DEFAULT_PER_PAGE): string
30 {
31 return $this->buildBalanceSettlementUrl($page, $perPage, self::ACTIVE_STATUSES, true);
32 }
33
34 public function getHistoryUrl(int $page = 1, int $perPage = self::DEFAULT_PER_PAGE): string
35 {
36 return $this->buildBalanceSettlementUrl($page, $perPage);
37 }
38
39 public function getBalance(): array
40 {
41 return $this->requestJson(self::BALANCE_URL);
42 }
43
44 public function getActiveSettlements(int $page = 1, int $perPage = self::DEFAULT_PER_PAGE): array
45 {
46 return $this->requestJson($this->getActiveSettlementsUrl($page, $perPage));
47 }
48
49 public function getSettlementHistory(int $page = 1, int $perPage = self::DEFAULT_PER_PAGE): array
50 {
51 return $this->requestJson($this->getHistoryUrl($page, $perPage));
52 }
53
54 public function getBankAccounts(): array
55 {
56 return $this->requestJson(self::BANK_ACCOUNTS_URL);
57 }
58
59 public function createSettlement(int $amount, int $method, ?int $investmentOptionId = null, ?int $bankAccountId = null): array
60 {
61 $body = [
62 'amount' => $amount,
63 'method' => $method,
64 ];
65
66 if ($investmentOptionId !== null) {
67 $body['investment_option_id'] = $investmentOptionId;
68 }
69
70 if ($bankAccountId !== null) {
71 $body['bank_account_id'] = $bankAccountId;
72 }
73
74 return $this->postJson(self::BALANCE_SETTLEMENT_POST_URL, $body);
75 }
76
77 public function getToken(): string
78 {
79 if (function_exists('syncBasalamSettings') && class_exists(SettingsConfig::class)) {
80 $token = syncBasalamSettings()->getSettings(SettingsConfig::TOKEN);
81 return is_string($token) ? trim($token) : '';
82 }
83
84 $settings = get_option('sync_basalam_settings', []);
85 if (!is_array($settings)) {
86 return '';
87 }
88
89 $token = $settings['token'] ?? '';
90 return is_string($token) ? trim($token) : '';
91 }
92
93 private function requestJson(string $url): array
94 {
95 return $this->sendJsonRequest('GET', $url);
96 }
97
98 private function postJson(string $url, array $body): array
99 {
100 return $this->sendJsonRequest('POST', $url, $body);
101 }
102
103 private function sendJsonRequest(string $method, string $url, ?array $body = null): array
104 {
105 $token = $this->getToken();
106 if ($token === '') {
107 return [
108 'success' => false,
109 'status_code' => 0,
110 'message' => 'توکن باسلا�
111 یافت نشد. ابتدا اتصال باسلا�
112 را در افزونه اصلی ووسلا�
113 انجا�
114 دهید.',
115 'data' => [],
116 'raw_body' => '',
117 ];
118 }
119
120 $args = [
121 'method' => $method,
122 'timeout' => 20,
123 'headers' => [
124 'Authorization' => 'Bearer ' . $token,
125 'Accept' => 'application/json',
126 'Content-Type' => 'application/json',
127 'user-agent' => 'Wp-Basalam',
128 'referer' => get_site_url(),
129 ],
130 ];
131
132
133 if ($body !== null) {
134 $args['body'] = wp_json_encode($body);
135 }
136
137 $response = wp_remote_request($url, $args);
138
139 if (is_wp_error($response)) {
140 return [
141 'success' => false,
142 'status_code' => 0,
143 'message' => $response->get_error_message(),
144 'data' => [],
145 'raw_body' => '',
146 ];
147 }
148
149 $statusCode = (int) wp_remote_retrieve_response_code($response);
150 $body = (string) wp_remote_retrieve_body($response);
151 $decoded = $this->decodeJsonResponse($body);
152
153 if ($statusCode < 200 || $statusCode > 299) {
154 return [
155 'success' => false,
156 'status_code' => $statusCode,
157 'message' => $this->extractErrorMessage($decoded, $body, $statusCode),
158 'data' => is_array($decoded) ? $decoded : [],
159 'raw_body' => $body,
160 ];
161 }
162
163 if (!is_array($decoded)) {
164 return [
165 'success' => false,
166 'status_code' => $statusCode,
167 'message' => 'پاسخ API قابل تبدیل به JSON نیست.',
168 'data' => [],
169 'raw_body' => $body,
170 ];
171 }
172
173 return [
174 'success' => true,
175 'status_code' => $statusCode,
176 'message' => '',
177 'data' => $decoded,
178 'raw_body' => $body,
179 ];
180 }
181
182 private function buildBalanceSettlementUrl(int $page, int $perPage, array $statuses = [], bool $withStatusFilter = false): string
183 {
184 $page = max(1, $page);
185 $perPage = max(1, $perPage);
186
187 $params = [
188 'page' => $page,
189 'per_page' => $perPage,
190 ];
191
192 if ($withStatusFilter) {
193 $params['status_filter_type'] = self::ACTIVE_STATUS_FILTER_TYPE;
194 }
195
196 $query = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
197
198 foreach ($statuses as $status) {
199 $query .= '&status=' . rawurlencode((string) $status);
200 }
201
202 return self::BALANCE_SETTLEMENT_URL . '?' . $query;
203 }
204
205 private function decodeJsonResponse(string $body): ?array
206 {
207 $trimmed = trim($body);
208 if ($trimmed === '') {
209 return null;
210 }
211
212 $decoded = json_decode($trimmed, true);
213 if (is_array($decoded) && json_last_error() === JSON_ERROR_NONE) {
214 return $decoded;
215 }
216
217 $start = strpos($trimmed, '{');
218 $end = strrpos($trimmed, '}');
219
220 if ($start !== false && $end !== false && $end > $start) {
221 $candidate = substr($trimmed, $start, ($end - $start + 1));
222 $decodedCandidate = json_decode($candidate, true);
223 if (is_array($decodedCandidate) && json_last_error() === JSON_ERROR_NONE) {
224 return $decodedCandidate;
225 }
226 }
227
228 return null;
229 }
230
231 private function extractErrorMessage($decodedBody, string $rawBody, int $statusCode): string
232 {
233 if (is_array($decodedBody)) {
234 if (!empty($decodedBody['message']) && is_string($decodedBody['message'])) {
235 return $decodedBody['message'] . ' (کد ' . $statusCode . ')';
236 }
237
238 if (!empty($decodedBody['error']) && is_string($decodedBody['error'])) {
239 return $decodedBody['error'] . ' (کد ' . $statusCode . ')';
240 }
241
242 if (!empty($decodedBody['errors'][0]['message']) && is_string($decodedBody['errors'][0]['message'])) {
243 return $decodedBody['errors'][0]['message'] . ' (کد ' . $statusCode . ')';
244 }
245 }
246
247 if ($rawBody !== '') {
248 return 'خطای API با کد ' . $statusCode . ': ' . wp_strip_all_tags($rawBody);
249 }
250
251 return 'خطای API با کد ' . $statusCode;
252 }
253 }
254