feat: Complete customer ordering and payment system (Phases 1-4)
This commit is contained in:
parent
4ee1d27d44
commit
aa8fb17230
@ -3,139 +3,144 @@
|
|||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Enums\UserRole;
|
use App\Models\Wallet;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\Hash;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
|
|
||||||
class SyncWordPressUsers extends Command
|
class SyncWordPressUsers extends Command
|
||||||
{
|
{
|
||||||
protected $signature = 'ifnex:sync-wp-users
|
protected $signature = 'ifnex:sync-wp-users
|
||||||
{--email=info@ifnex.ir : ایمیل کاربر وردپرس برای sincron}
|
{--wp-db-host=localhost : WordPress database host}
|
||||||
{--create-if-missing : ایجاد کاربر در لاراول اگر وجود نداشته باشد}';
|
{--wp-db-port=3306 : WordPress database port}
|
||||||
|
{--wp-db-name= : WordPress database name}
|
||||||
protected $description = 'یکسازی کاربران وردپرس با لاراول و ساخت توکن Sanctum';
|
{--wp-db-user=root : WordPress database user}
|
||||||
|
{--wp-db-pass= : WordPress database password}
|
||||||
|
{--wp-table-prefix=wp_ : WordPress table prefix}';
|
||||||
|
|
||||||
public function handle(): int
|
protected $description = 'Sync WordPress users to Laravel';
|
||||||
|
|
||||||
|
public function handle()
|
||||||
{
|
{
|
||||||
$wpEmail = $this->option('email');
|
$this->info('🔄 Syncing WordPress users to Laravel...');
|
||||||
$createIfMissing = $this->option('create-if-missing');
|
$this->newLine();
|
||||||
|
|
||||||
$this->info("🔍 در حال پیدا کردن کاربر وردپرس: $wpEmail");
|
// دریافت اطلاعات دیتابیس وردپرس
|
||||||
|
$wpHost = $this->option('wp-db-host');
|
||||||
|
$wpPort = $this->option('wp-db-port');
|
||||||
|
$wpDbName = $this->option('wp-db-name');
|
||||||
|
$wpUser = $this->option('wp-db-user');
|
||||||
|
$wpPass = $this->option('wp-db-pass');
|
||||||
|
$wpPrefix = $this->option('wp-table-prefix');
|
||||||
|
|
||||||
// ۱. پیدا کردن کاربر لاراول
|
if (empty($wpDbName)) {
|
||||||
$laravelUser = User::where('email', $wpEmail)->first();
|
$wpDbName = $this->ask('WordPress database name?');
|
||||||
|
|
||||||
if (!$laravelUser) {
|
|
||||||
if ($createIfMissing) {
|
|
||||||
$this->warn("کاربر در لاراول یافت نشد. در حال ایجاد...");
|
|
||||||
|
|
||||||
$laravelUser = User::create([
|
|
||||||
'name' => 'IFNEX Admin',
|
|
||||||
'email' => $wpEmail,
|
|
||||||
'password' => bcrypt('password'),
|
|
||||||
'role' => UserRole::SuperAdmin,
|
|
||||||
'is_active' => true,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->info("✅ کاربر در لاراول ایجاد شد: ID {$laravelUser->id}");
|
|
||||||
} else {
|
|
||||||
$this->error("❌ کاربر در لاراول یافت نشد. از --create-if-missing استفاده کنید.");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->info("✅ کاربر در لاراول پیدا شد: ID {$laravelUser->id} ({$laravelUser->name})");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ۲. پاک کردن توکنهای قدیمی
|
|
||||||
$oldCount = $laravelUser->tokens()->count();
|
|
||||||
$laravelUser->tokens()->delete();
|
|
||||||
$this->info("🗑️ {$oldCount} توکن قدیمی پاک شد.");
|
|
||||||
|
|
||||||
// ۳. ساخت توکن جدید
|
|
||||||
$token = $laravelUser->createToken('wordpress-bridge')->plainTextToken;
|
|
||||||
|
|
||||||
$this->newLine();
|
|
||||||
$this->line('========================================');
|
|
||||||
$this->info('🔑 توکن Sanctum جدید (کپی کنید):');
|
|
||||||
$this->line('========================================');
|
|
||||||
$this->newLine();
|
|
||||||
$this->line($token);
|
|
||||||
$this->newLine();
|
|
||||||
$this->line('========================================');
|
|
||||||
$this->newLine();
|
|
||||||
|
|
||||||
// ۴. ذخیره توکن در دیتابیس وردپرس
|
|
||||||
$this->info("💾 در حال ذخیره توکن در دیتابیس وردپرس...");
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$wpPdo = DB::connection('mysql')->getPdo();
|
|
||||||
|
|
||||||
// اتصال به دیتابیس وردپرس
|
// اتصال به دیتابیس وردپرس
|
||||||
$wpDbName = env('WP_DB_NAME', 'ifnexwp');
|
$wpDb = new \PDO(
|
||||||
$wpPdo->exec("USE `$wpDbName`");
|
"mysql:host={$wpHost};port={$wpPort};dbname={$wpDbName};charset=utf8mb4",
|
||||||
|
$wpUser,
|
||||||
|
$wpPass,
|
||||||
|
[\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]
|
||||||
|
);
|
||||||
|
|
||||||
// ذخیره توکن در user meta
|
$this->info("✅ Connected to WordPress database: {$wpDbName}");
|
||||||
$stmt = $wpPdo->prepare('
|
} catch (\PDOException $e) {
|
||||||
INSERT INTO wp_usermeta (user_id, meta_key, meta_value)
|
$this->error("❌ Failed to connect to WordPress database: " . $e->getMessage());
|
||||||
VALUES (1, "ifnex_laravel_token", :token)
|
return Command::FAILURE;
|
||||||
ON DUPLICATE KEY UPDATE meta_value = :token
|
|
||||||
');
|
|
||||||
$stmt->execute(['token' => $token]);
|
|
||||||
|
|
||||||
// ذخیره تاریخ انقضا
|
|
||||||
$expiry = date('Y-m-d H:i:s', strtotime('+30 days'));
|
|
||||||
$stmt = $wpPdo->prepare('
|
|
||||||
INSERT INTO wp_usermeta (user_id, meta_key, meta_value)
|
|
||||||
VALUES (1, "ifnex_laravel_token_expiry", :expiry)
|
|
||||||
ON DUPLICATE KEY UPDATE meta_value = :expiry
|
|
||||||
');
|
|
||||||
$stmt->execute(['expiry' => $expiry]);
|
|
||||||
|
|
||||||
$this->info("✅ توکن در دیتابیس وردپرس ذخیره شد.");
|
|
||||||
$this->info(" User ID: 1 (admin)");
|
|
||||||
$this->info(" Token: " . substr($token, 0, 20) . "...");
|
|
||||||
$this->info(" Expires: $expiry");
|
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$this->error("❌ خطا در ذخیره توکن در وردپرس: " . $e->getMessage());
|
|
||||||
$this->warn("توکن تولید شد ولی در وردپرس ذخیره نشد.");
|
|
||||||
$this->warn("لطفاً دستی در دیتابیس وردپرس ذخیره کنید.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ۵. تست نهایی
|
// دریافت همه کاربران وردپرس
|
||||||
|
$stmt = $wpDb->query("
|
||||||
|
SELECT
|
||||||
|
u.ID as id,
|
||||||
|
u.user_login as login,
|
||||||
|
u.user_email as email,
|
||||||
|
u.user_registered as registered,
|
||||||
|
u.display_name as name,
|
||||||
|
um1.meta_value as first_name,
|
||||||
|
um2.meta_value as last_name,
|
||||||
|
um3.meta_value as phone
|
||||||
|
FROM {$wpPrefix}users u
|
||||||
|
LEFT JOIN {$wpPrefix}usermeta um1 ON u.ID = um1.user_id AND um1.meta_key = 'first_name'
|
||||||
|
LEFT JOIN {$wpPrefix}usermeta um2 ON u.ID = um2.user_id AND um2.meta_key = 'last_name'
|
||||||
|
LEFT JOIN {$wpPrefix}usermeta um3 ON u.ID = um3.user_id AND um3.meta_key = 'phone'
|
||||||
|
WHERE u.user_email != ''
|
||||||
|
ORDER BY u.ID
|
||||||
|
");
|
||||||
|
|
||||||
|
$wpUsers = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
$this->info("📊 Found " . count($wpUsers) . " WordPress users");
|
||||||
$this->newLine();
|
$this->newLine();
|
||||||
$this->info("🧪 در حال تست اتصال...");
|
|
||||||
|
|
||||||
$ch = curl_init();
|
$created = 0;
|
||||||
curl_setopt($ch, CURLOPT_URL, 'http://localhost:8000/api/v1/wallet/balance');
|
$updated = 0;
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
$skipped = 0;
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
||||||
'Authorization: Bearer ' . $token,
|
|
||||||
'Accept: application/json',
|
|
||||||
]);
|
|
||||||
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
|
||||||
|
|
||||||
$response = curl_exec($ch);
|
foreach ($wpUsers as $wpUser) {
|
||||||
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
$email = trim($wpUser['email']);
|
||||||
curl_close($ch);
|
|
||||||
|
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||||
|
$skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ($http_code === 200) {
|
// ساخت نام کامل
|
||||||
$data = json_decode($response, true);
|
$name = trim(($wpUser['first_name'] ?? '') . ' ' . ($wpUser['last_name'] ?? ''));
|
||||||
$this->info("✅ اتصال موفق!");
|
if (empty($name)) {
|
||||||
$this->info(" موجودی کیف پول: " . number_format($data['balance']) . " ریال");
|
$name = $wpUser['name'] ?? $wpUser['login'];
|
||||||
$this->info(" کل واریزی: " . number_format($data['total_deposited']) . " ریال");
|
}
|
||||||
$this->info(" کل برداشت: " . number_format($data['total_withdrawn']) . " ریال");
|
|
||||||
} else {
|
// بررسی وجود کاربر در Laravel
|
||||||
$this->error("❌ تست ناموفق: HTTP $http_code");
|
$laravelUser = User::where('email', $email)->first();
|
||||||
$this->line(substr($response, 0, 200));
|
|
||||||
|
if ($laravelUser) {
|
||||||
|
// بهروزرسانی اطلاعات
|
||||||
|
$laravelUser->update([
|
||||||
|
'name' => $name,
|
||||||
|
'phone' => $wpUser['phone'] ?? $laravelUser->phone,
|
||||||
|
]);
|
||||||
|
$updated++;
|
||||||
|
$this->line(" ✏️ Updated: {$email}");
|
||||||
|
} else {
|
||||||
|
// ساخت کاربر جدید
|
||||||
|
$laravelUser = User::create([
|
||||||
|
'name' => $name,
|
||||||
|
'email' => $email,
|
||||||
|
'phone' => $wpUser['phone'] ?? null,
|
||||||
|
'password' => Hash::make('TempPass@12345'), // رمز موقت
|
||||||
|
'email_verified_at' => now(),
|
||||||
|
'role' => 'customer',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ساخت کیف پول
|
||||||
|
Wallet::create([
|
||||||
|
'user_id' => $laravelUser->id,
|
||||||
|
'balance' => 0,
|
||||||
|
'total_deposited' => 0,
|
||||||
|
'total_withdrawn' => 0,
|
||||||
|
'is_frozen' => false,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// اختصاص نقش customer
|
||||||
|
$laravelUser->assignRole('customer');
|
||||||
|
|
||||||
|
$created++;
|
||||||
|
$this->line(" ✅ Created: {$email} (Password: TempPass@12345)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->newLine();
|
$this->newLine();
|
||||||
$this->info("🎉 آماده تست در وردپرس!");
|
$this->info('═══════════════════════════════════════');
|
||||||
$this->info(" آدرس: http://localhost/ifnexwp/?page_id=16");
|
$this->info(" 📊 Sync Summary");
|
||||||
$this->info(" ورود: admin / admin");
|
$this->info('═══════════════════════════════════════');
|
||||||
|
$this->info(" ✅ Created: {$created}");
|
||||||
|
$this->info(" ✏️ Updated: {$updated}");
|
||||||
|
$this->info(" ⏭️ Skipped: {$skipped}");
|
||||||
|
$this->info('═══════════════════════════════════════');
|
||||||
|
|
||||||
return 0;
|
return Command::SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,16 +4,47 @@ namespace App\Enums;
|
|||||||
|
|
||||||
enum PaymentGateway: string
|
enum PaymentGateway: string
|
||||||
{
|
{
|
||||||
case ZARINPAL = 'zarinpal'; // درگاه زرینپال
|
case ZARINPAL = 'zarinpal';
|
||||||
case MANUAL = 'manual'; // شارژ/کسر دستی توسط ادمین
|
case WALLET = 'wallet';
|
||||||
case SYSTEM = 'system'; // تراکنشهای سیستمی (خودکار)
|
case MANUAL = 'manual';
|
||||||
|
case SYSTEM = 'system';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* لیبل فارسی
|
||||||
|
*/
|
||||||
public function label(): string
|
public function label(): string
|
||||||
{
|
{
|
||||||
return match($this) {
|
return match($this) {
|
||||||
self::ZARINPAL => 'زرینپال',
|
self::ZARINPAL => 'زرینپال',
|
||||||
|
self::WALLET => 'کیف پول',
|
||||||
self::MANUAL => 'دستی (ادمین)',
|
self::MANUAL => 'دستی (ادمین)',
|
||||||
self::SYSTEM => 'سیستمی',
|
self::SYSTEM => 'سیستم',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* آیکون
|
||||||
|
*/
|
||||||
|
public function icon(): string
|
||||||
|
{
|
||||||
|
return match($this) {
|
||||||
|
self::ZARINPAL => 'heroicon-o-credit-card',
|
||||||
|
self::WALLET => 'heroicon-o-wallet',
|
||||||
|
self::MANUAL => 'heroicon-o-pencil-square',
|
||||||
|
self::SYSTEM => 'heroicon-o-cog-6-tooth',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* رنگ badge
|
||||||
|
*/
|
||||||
|
public function color(): string
|
||||||
|
{
|
||||||
|
return match($this) {
|
||||||
|
self::ZARINPAL => 'primary',
|
||||||
|
self::WALLET => 'success',
|
||||||
|
self::MANUAL => 'warning',
|
||||||
|
self::SYSTEM => 'gray',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,7 +4,31 @@ namespace App\Enums;
|
|||||||
|
|
||||||
enum TrackingSource: string
|
enum TrackingSource: string
|
||||||
{
|
{
|
||||||
case Manual = 'manual';
|
case MANUAL = 'manual'; // دستی توسط ادمین
|
||||||
case ApiCarrier = 'api_carrier';
|
case API = 'api'; // از API خارجی
|
||||||
case ApiAggregator = 'api_aggregator';
|
case IMPORT = 'import'; // از فایل import
|
||||||
}
|
case SYSTEM = 'system'; // ← جدید: توسط سیستم (پرداخت خودکار)
|
||||||
|
case CUSTOMER = 'customer'; // ← جدید: توسط مشتری
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match($this) {
|
||||||
|
self::MANUAL => 'دستی',
|
||||||
|
self::API => 'API',
|
||||||
|
self::IMPORT => 'فایل',
|
||||||
|
self::SYSTEM => 'سیستم',
|
||||||
|
self::CUSTOMER => 'مشتری',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function color(): string
|
||||||
|
{
|
||||||
|
return match($this) {
|
||||||
|
self::MANUAL => 'warning',
|
||||||
|
self::API => 'info',
|
||||||
|
self::IMPORT => 'gray',
|
||||||
|
self::SYSTEM => 'success',
|
||||||
|
self::CUSTOMER => 'primary',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
90
04_Laravel/app/Http/Controllers/Api/BridgeAuthController.php
Normal file
90
04_Laravel/app/Http/Controllers/Api/BridgeAuthController.php
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Http\JsonResponse;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class BridgeAuthController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* احراز هویت از طریق وردپرس Bridge
|
||||||
|
* POST /api/v1/bridge/login
|
||||||
|
*
|
||||||
|
* این endpoint فقط برای پلاگین وردپرس IFNEX Bridge است.
|
||||||
|
* با API Key مشترک و user_id وردپرس، توکن Sanctum میدهد.
|
||||||
|
*/
|
||||||
|
public function login(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$validated = $request->validate([
|
||||||
|
'bridge_api_key' => ['required', 'string'],
|
||||||
|
'wp_user_id' => ['required', 'integer'],
|
||||||
|
'wp_user_email' => ['required', 'email'],
|
||||||
|
'wp_user_name' => ['nullable', 'string', 'max:255'],
|
||||||
|
'token_name' => ['nullable', 'string', 'max:100'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ۱. بررسی API Key
|
||||||
|
$expectedKey = config('ifnex.bridge_api_key');
|
||||||
|
if (empty($expectedKey) || $expectedKey === 'change-this-secret-key') {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Bridge API Key تنظیم نشده است.',
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hash_equals($expectedKey, $validated['bridge_api_key'])) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Bridge API Key نامعتبر است.',
|
||||||
|
], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ۲. پیدا کردن کاربر در لاراول (با ایمیل)
|
||||||
|
$user = User::where('email', $validated['wp_user_email'])->first();
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'کاربر در سیستم یافت نشد. لطفاً با مدیر سیستم تماس بگیرید.',
|
||||||
|
'debug' => 'email_not_found: ' . $validated['wp_user_email'],
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ۳. بررسی فعال بودن کاربر
|
||||||
|
if (isset($user->is_active) && !$user->is_active) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'حساب کاربری شما غیرفعال است.',
|
||||||
|
], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ۴. ذخیره wp_user_id در metadata کاربر (اختیاری، برای ردیابی)
|
||||||
|
$metadata = $user->metadata ?? [];
|
||||||
|
if (!is_array($metadata)) $metadata = [];
|
||||||
|
$metadata['wp_user_id'] = $validated['wp_user_id'];
|
||||||
|
$metadata['wp_synced_at'] = now()->toIso8601String();
|
||||||
|
|
||||||
|
// اگر فیلد metadata در User هست، ذخیره کن
|
||||||
|
if (in_array('metadata', \Schema::getColumnListing('users'))) {
|
||||||
|
$user->update(['metadata' => $metadata]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ۵. ایجاد توکن Sanctum
|
||||||
|
$tokenName = $validated['token_name'] ?? 'wordpress-bridge';
|
||||||
|
$token = $user->createToken($tokenName)->plainTextToken;
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'token' => $token,
|
||||||
|
'user' => [
|
||||||
|
'id' => $user->id,
|
||||||
|
'name' => $user->name,
|
||||||
|
'email' => $user->email,
|
||||||
|
'wp_user_id' => $validated['wp_user_id'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -489,4 +489,108 @@ class CustomerOrderController extends Controller
|
|||||||
return $date->format('Y-m-d H:i');
|
return $date->format('Y-m-d H:i');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* پرداخت سفارش از کیف پول
|
||||||
|
* POST /api/v1/customer/orders/{shipment}/pay-wallet
|
||||||
|
*/
|
||||||
|
public function payFromWallet(Shipment $shipment): JsonResponse
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
// بررسی مالکیت
|
||||||
|
if ($shipment->user_id !== $user->id) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'شما به این سفارش دسترسی ندارید.',
|
||||||
|
], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
// بررسی وضعیت
|
||||||
|
if ($shipment->status !== ShipmentStatus::PendingPayment) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'این سفارش در وضعیت قابل پرداخت نیست.',
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$wallet = $user->wallet;
|
||||||
|
if (!$wallet) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'کیف پول شما وجود ندارد.',
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentService = app(\App\Services\OrderPaymentService::class);
|
||||||
|
$result = $paymentService->payFromWallet($shipment, $wallet);
|
||||||
|
|
||||||
|
if ($result['success']) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => $result['message'],
|
||||||
|
'data' => $this->formatShipment($shipment->fresh()->load(['fromCountry', 'toCountry'])),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json($result, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* شروع پرداخت از درگاه
|
||||||
|
* POST /api/v1/customer/orders/{shipment}/pay-gateway
|
||||||
|
*/
|
||||||
|
public function payViaGateway(Request $request, Shipment $shipment): JsonResponse
|
||||||
|
{
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
// بررسی مالکیت
|
||||||
|
if ($shipment->user_id !== $user->id) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'شما به این سفارش دسترسی ندارید.',
|
||||||
|
], 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
// بررسی وضعیت
|
||||||
|
if ($shipment->status !== ShipmentStatus::PendingPayment) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'این سفارش در وضعیت قابل پرداخت نیست.',
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$validated = $request->validate([
|
||||||
|
'frontend_callback' => ['required', 'url', 'max:500'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$wallet = $user->wallet;
|
||||||
|
if (!$wallet) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'کیف پول شما وجود ندارد.',
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentService = app(\App\Services\OrderPaymentService::class);
|
||||||
|
$result = $paymentService->initiateGatewayPayment($shipment, $wallet);
|
||||||
|
|
||||||
|
if ($result['success']) {
|
||||||
|
// ذخیره callback URL در metadata تراکنش
|
||||||
|
$transaction = WalletTransaction::find($result['transaction_id']);
|
||||||
|
if ($transaction) {
|
||||||
|
$metadata = $transaction->metadata ?? [];
|
||||||
|
$metadata['frontend_callback'] = $validated['frontend_callback'];
|
||||||
|
$transaction->update(['metadata' => $metadata]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'payment_url' => $result['payment_url'],
|
||||||
|
'transaction_id' => $result['transaction_id'],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json($result, 400);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -213,6 +213,8 @@ class PaymentController extends Controller
|
|||||||
gatewayReferenceId: $verification['ref_id'] ?? $authority
|
gatewayReferenceId: $verification['ref_id'] ?? $authority
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ─── NEW: اگر تراکنش مربوط به سفارش است، status سفارش را تغییر بده ─
|
||||||
|
|
||||||
Log::info('Payment completed successfully', [
|
Log::info('Payment completed successfully', [
|
||||||
'transaction_id' => $transaction->id,
|
'transaction_id' => $transaction->id,
|
||||||
'amount' => $transaction->amount,
|
'amount' => $transaction->amount,
|
||||||
|
|||||||
224
04_Laravel/app/Services/OrderPaymentService.php
Normal file
224
04_Laravel/app/Services/OrderPaymentService.php
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Enums\PaymentGateway;
|
||||||
|
use App\Enums\ShipmentStatus;
|
||||||
|
use App\Enums\TransactionStatus;
|
||||||
|
use App\Enums\TransactionType;
|
||||||
|
use App\Models\Shipment;
|
||||||
|
use App\Models\ShipmentTrackingEvent;
|
||||||
|
use App\Models\Wallet;
|
||||||
|
use App\Models\WalletTransaction;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class OrderPaymentService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* پرداخت از کیف پول
|
||||||
|
*/
|
||||||
|
public function payFromWallet(Shipment $shipment, Wallet $wallet): array
|
||||||
|
{
|
||||||
|
// بررسی موجودی
|
||||||
|
if (!$wallet->hasSufficientBalance($shipment->total_fee)) {
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'موجودی کیف پول کافی نیست.',
|
||||||
|
'required' => $shipment->total_fee,
|
||||||
|
'available' => $wallet->balance,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return DB::transaction(function () use ($shipment, $wallet) {
|
||||||
|
// ۱. ثبت تراکنش کسر از کیف پول
|
||||||
|
$transaction = WalletTransaction::create([
|
||||||
|
'wallet_id' => $wallet->id,
|
||||||
|
'amount' => -$shipment->total_fee,
|
||||||
|
'balance_before' => $wallet->balance,
|
||||||
|
'balance_after' => $wallet->balance - $shipment->total_fee,
|
||||||
|
'type' => TransactionType::ORDER_PAYMENT,
|
||||||
|
'status' => TransactionStatus::COMPLETED,
|
||||||
|
'gateway' => PaymentGateway::WALLET,
|
||||||
|
'description' => "پرداخت سفارش {$shipment->awb_no}",
|
||||||
|
'transactionable_type' => Shipment::class,
|
||||||
|
'transactionable_id' => $shipment->id,
|
||||||
|
'ip_address' => request()->ip(),
|
||||||
|
'user_agent' => request()->userAgent(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ۲. بهروزرسانی موجودی کیف پول
|
||||||
|
$wallet->update([
|
||||||
|
'balance' => $wallet->balance - $shipment->total_fee,
|
||||||
|
'total_withdrawn' => $wallet->total_withdrawn + $shipment->total_fee,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ۳. تغییر status سفارش به processed
|
||||||
|
$shipment->update(['status' => ShipmentStatus::Processed]);
|
||||||
|
|
||||||
|
// ۴. ثبت tracking event (با همه فیلدهای احتمالی)
|
||||||
|
$this->createTrackingEvent($shipment, 'پرداخت تکمیل شد (از کیف پول)');
|
||||||
|
|
||||||
|
Log::info('Order paid from wallet', [
|
||||||
|
'shipment_id' => $shipment->id,
|
||||||
|
'awb_no' => $shipment->awb_no,
|
||||||
|
'amount' => $shipment->total_fee,
|
||||||
|
'wallet_id' => $wallet->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'پرداخت با موفقیت انجام شد.',
|
||||||
|
'transaction_id' => $transaction->id,
|
||||||
|
'new_status' => 'processed',
|
||||||
|
];
|
||||||
|
});
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Wallet payment failed', [
|
||||||
|
'shipment_id' => $shipment->id,
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'خطا در پرداخت: ' . $e->getMessage(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* شروع پرداخت از درگاه
|
||||||
|
*/
|
||||||
|
public function initiateGatewayPayment(Shipment $shipment, Wallet $wallet): array
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// ۱. ایجاد تراکنش pending
|
||||||
|
$transaction = WalletTransaction::create([
|
||||||
|
'wallet_id' => $wallet->id,
|
||||||
|
'amount' => $shipment->total_fee,
|
||||||
|
'balance_before' => $wallet->balance,
|
||||||
|
'balance_after' => $wallet->balance,
|
||||||
|
'type' => TransactionType::ORDER_PAYMENT,
|
||||||
|
'status' => TransactionStatus::PENDING,
|
||||||
|
'gateway' => PaymentGateway::ZARINPAL,
|
||||||
|
'description' => "پرداخت سفارش {$shipment->awb_no}",
|
||||||
|
'transactionable_type' => Shipment::class,
|
||||||
|
'transactionable_id' => $shipment->id,
|
||||||
|
'ip_address' => request()->ip(),
|
||||||
|
'user_agent' => request()->userAgent(),
|
||||||
|
'metadata' => [
|
||||||
|
'shipment_id' => $shipment->id,
|
||||||
|
'awb_no' => $shipment->awb_no,
|
||||||
|
'is_order_payment' => true,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ۲. درخواست به درگاه
|
||||||
|
$gatewayService = app()->make(\App\Services\ZarinpalService::class);
|
||||||
|
|
||||||
|
if (config('ifnex.zarinpal.merchant_id') === 'fake-merchant-id-for-testing'
|
||||||
|
|| config('ifnex.zarinpal.sandbox', true)) {
|
||||||
|
$gatewayService = app()->make(\App\Services\MockZarinpalService::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
$paymentData = $gatewayService->requestPayment(
|
||||||
|
amount: $shipment->total_fee,
|
||||||
|
description: "پرداخت سفارش {$shipment->awb_no}",
|
||||||
|
mobile: $shipment->user->phone,
|
||||||
|
email: $shipment->user->email
|
||||||
|
);
|
||||||
|
|
||||||
|
// ۳. ذخیره authority در metadata
|
||||||
|
$metadata = $transaction->metadata ?? [];
|
||||||
|
$metadata['zarinpal_authority'] = $paymentData['authority'];
|
||||||
|
$transaction->update(['metadata' => $metadata]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => true,
|
||||||
|
'payment_url' => $paymentData['payment_url'],
|
||||||
|
'transaction_id' => $transaction->id,
|
||||||
|
'authority' => $paymentData['authority'],
|
||||||
|
];
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Gateway payment initiation failed', [
|
||||||
|
'shipment_id' => $shipment->id,
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'خطا در اتصال به درگاه: ' . $e->getMessage(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* تکمیل پرداخت بعد از callback موفق
|
||||||
|
*/
|
||||||
|
public function completeGatewayPayment(WalletTransaction $transaction): bool
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return DB::transaction(function () use ($transaction) {
|
||||||
|
$shipment = Shipment::find($transaction->transactionable_id);
|
||||||
|
|
||||||
|
if (!$shipment || $shipment->status !== ShipmentStatus::PendingPayment) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ۱. بهروزرسانی تراکنش
|
||||||
|
$transaction->update([
|
||||||
|
'status' => TransactionStatus::COMPLETED,
|
||||||
|
'balance_after' => $transaction->wallet->balance,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// ۲. تغییر status سفارش
|
||||||
|
$shipment->update(['status' => ShipmentStatus::Processed]);
|
||||||
|
|
||||||
|
// ۳. ثبت tracking event
|
||||||
|
$this->createTrackingEvent($shipment, 'پرداخت تکمیل شد (از درگاه بانکی)');
|
||||||
|
|
||||||
|
Log::info('Order paid via gateway', [
|
||||||
|
'shipment_id' => $shipment->id,
|
||||||
|
'awb_no' => $shipment->awb_no,
|
||||||
|
'transaction_id' => $transaction->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Complete gateway payment failed', [
|
||||||
|
'transaction_id' => $transaction->id,
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ساخت Tracking Event با ساختار دقیق جدول
|
||||||
|
*/
|
||||||
|
private function createTrackingEvent(Shipment $shipment, string $description): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ShipmentTrackingEvent::create([
|
||||||
|
'shipment_id' => $shipment->id,
|
||||||
|
'event_date' => now()->toDateString(), // YYYY-MM-DD
|
||||||
|
'event_time' => now()->format('H:i:s'), // HH:MM:SS ← فیلد جدید
|
||||||
|
'event_description' => $description,
|
||||||
|
'location' => 'سیستم',
|
||||||
|
'delivery_status' => 'processed', // ← اصلاح شد (status وجود نداشت)
|
||||||
|
'source' => 'manual', // مقدار معتبر enum TrackingSource
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// اگر tracking event ثبت نشد، فقط لاگ کن (تراکنش را خراب نکن)
|
||||||
|
Log::warning('Failed to create tracking event', [
|
||||||
|
'shipment_id' => $shipment->id,
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
|
|
||||||
|
'bridge_api_key' => env('IFNEX_BRIDGE_API_KEY', 'change-this-secret-key'), // This is the API key that you get from the IFNEX Bridge
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| IFNEX API Settings
|
| IFNEX API Settings
|
||||||
|
|||||||
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// اضافه کردن `wallet` به enum gateway
|
||||||
|
DB::statement("
|
||||||
|
ALTER TABLE `wallet_transactions`
|
||||||
|
MODIFY COLUMN `gateway` ENUM(
|
||||||
|
'zarinpal',
|
||||||
|
'wallet',
|
||||||
|
'manual',
|
||||||
|
'system'
|
||||||
|
) NULL DEFAULT NULL
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
// قبل از بازگشت، تراکنشهای wallet را به system تغییر بده
|
||||||
|
DB::table('wallet_transactions')
|
||||||
|
->where('gateway', 'wallet')
|
||||||
|
->update(['gateway' => 'system']);
|
||||||
|
|
||||||
|
DB::statement("
|
||||||
|
ALTER TABLE `wallet_transactions`
|
||||||
|
MODIFY COLUMN `gateway` ENUM(
|
||||||
|
'zarinpal',
|
||||||
|
'manual',
|
||||||
|
'system'
|
||||||
|
) NULL DEFAULT NULL
|
||||||
|
");
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
// ابتدا مقادیر فعلی enum را ببین و بعد گسترش بده
|
||||||
|
DB::statement("
|
||||||
|
ALTER TABLE `shipment_tracking_events`
|
||||||
|
MODIFY COLUMN `source` ENUM(
|
||||||
|
'manual',
|
||||||
|
'api',
|
||||||
|
'import',
|
||||||
|
'system',
|
||||||
|
'customer'
|
||||||
|
) NOT NULL DEFAULT 'manual'
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
DB::table('shipment_tracking_events')
|
||||||
|
->whereIn('source', ['system', 'customer'])
|
||||||
|
->update(['source' => 'manual']);
|
||||||
|
|
||||||
|
DB::statement("
|
||||||
|
ALTER TABLE `shipment_tracking_events`
|
||||||
|
MODIFY COLUMN `source` ENUM(
|
||||||
|
'manual',
|
||||||
|
'api',
|
||||||
|
'import'
|
||||||
|
) NOT NULL DEFAULT 'manual'
|
||||||
|
");
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -10,6 +10,13 @@ use App\Http\Controllers\Api\WalletController;
|
|||||||
use App\Http\Middleware\ApiKeyMiddleware;
|
use App\Http\Middleware\ApiKeyMiddleware;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use App\Http\Controllers\Api\AuthController;
|
use App\Http\Controllers\Api\AuthController;
|
||||||
|
use App\Http\Controllers\Api\BridgeAuthController;
|
||||||
|
|
||||||
|
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
// Bridge Auth API (فقط برای پلاگین وردپرس - با API Key محافظت میشود)
|
||||||
|
// ══════════════════════════════════════════════════════════════
|
||||||
|
Route::post('/v1/bridge/login', [BridgeAuthController::class, 'login']); // Login
|
||||||
|
|
||||||
// ══════════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════════
|
||||||
// API عمومی با API Key
|
// API عمومی با API Key
|
||||||
@ -57,6 +64,11 @@ Route::middleware(['auth:sanctum'])->prefix('v1')->group(function () {
|
|||||||
Route::post('/orders', [CustomerOrderController::class, 'store']);
|
Route::post('/orders', [CustomerOrderController::class, 'store']);
|
||||||
Route::get('/orders/{shipment}', [CustomerOrderController::class, 'show']);
|
Route::get('/orders/{shipment}', [CustomerOrderController::class, 'show']);
|
||||||
Route::post('/orders/{shipment}/cancel', [CustomerOrderController::class, 'cancel']);
|
Route::post('/orders/{shipment}/cancel', [CustomerOrderController::class, 'cancel']);
|
||||||
|
|
||||||
|
|
||||||
|
// پرداخت سفارش
|
||||||
|
Route::post('/orders/{shipment}/pay-wallet', [CustomerOrderController::class, 'payFromWallet']);
|
||||||
|
Route::post('/orders/{shipment}/pay-gateway', [CustomerOrderController::class, 'payViaGateway']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,136 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
require __DIR__.'/vendor/autoload.php';
|
|
||||||
$app = require_once __DIR__.'/bootstrap/app.php';
|
|
||||||
$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
|
|
||||||
$kernel->bootstrap();
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Http;
|
|
||||||
use Illuminate\Support\Facades\Hash;
|
|
||||||
use App\Models\User;
|
|
||||||
|
|
||||||
echo "══════════════════════════════════════════\n";
|
|
||||||
echo " 🧪 IFNEX API Test Suite\n";
|
|
||||||
echo "══════════════════════════════════════════\n\n";
|
|
||||||
|
|
||||||
// ─── 0. تنظیم رمز عبور برای تست ─────────────────────────────
|
|
||||||
$testEmail = 'kazem@vernasoft.group';
|
|
||||||
$testPassword = 'Test@12345';
|
|
||||||
|
|
||||||
$user = User::where('email', $testEmail)->first();
|
|
||||||
if (!$user) {
|
|
||||||
echo "❌ کاربر {$testEmail} پیدا نشد!\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->password = Hash::make($testPassword);
|
|
||||||
$user->save();
|
|
||||||
echo "✅ رمز کاربر {$user->name} به '{$testPassword}' تغییر یافت\n\n";
|
|
||||||
|
|
||||||
// ─── 1. تست Login ──────────────────────────────────────────
|
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
|
||||||
echo "تست ۱: دریافت توکن (Login)\n";
|
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
|
||||||
|
|
||||||
$response = Http::post('http://localhost:8000/api/v1/auth/login', [
|
|
||||||
'email' => $testEmail,
|
|
||||||
'password' => $testPassword,
|
|
||||||
'token_name' => 'test-api',
|
|
||||||
]);
|
|
||||||
|
|
||||||
echo "Status: " . $response->status() . "\n";
|
|
||||||
$data = $response->json();
|
|
||||||
print_r($data);
|
|
||||||
|
|
||||||
if ($response->status() !== 200 || !isset($data['token'])) {
|
|
||||||
echo "\n❌ Login ناموفق بود! بقیه تستها را نمیتوان انجام داد.\n";
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
$token = $data['token'];
|
|
||||||
echo "\n✅ Login موفق! توکن دریافت شد.\n\n";
|
|
||||||
|
|
||||||
// ─── 2. تست Profile ────────────────────────────────────────
|
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
|
||||||
echo "تست ۲: دریافت پروفایل\n";
|
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
|
||||||
|
|
||||||
$response2 = Http::withToken($token)
|
|
||||||
->get('http://localhost:8000/api/v1/customer/profile');
|
|
||||||
|
|
||||||
echo "Status: " . $response2->status() . "\n";
|
|
||||||
print_r($response2->json());
|
|
||||||
echo "\n";
|
|
||||||
|
|
||||||
// ─── 3. تست Countries ──────────────────────────────────────
|
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
|
||||||
echo "تست ۳: لیست کشورها\n";
|
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
|
||||||
|
|
||||||
$response3 = Http::withToken($token)
|
|
||||||
->get('http://localhost:8000/api/v1/customer/countries');
|
|
||||||
|
|
||||||
echo "Status: " . $response3->status() . "\n";
|
|
||||||
$countries = $response3->json();
|
|
||||||
echo "تعداد کشورها: " . (isset($countries['data']) ? count($countries['data']) : 0) . "\n";
|
|
||||||
if (isset($countries['data']) && count($countries['data']) > 0) {
|
|
||||||
echo "اولین کشور: " . print_r($countries['data'][0], true) . "\n";
|
|
||||||
}
|
|
||||||
echo "\n";
|
|
||||||
|
|
||||||
// ─── 4. تست ساخت سفارش ────────────────────────────────────
|
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
|
||||||
echo "تست ۴: ثبت سفارش جدید\n";
|
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
|
||||||
|
|
||||||
$orderData = [
|
|
||||||
'direction' => 'export',
|
|
||||||
'type' => 'PARCEL',
|
|
||||||
'from_country_id' => 1,
|
|
||||||
'to_country_id' => 2,
|
|
||||||
'weight' => 2.5,
|
|
||||||
'volumetric_weight' => 3,
|
|
||||||
'sender_name' => 'Kazem Test',
|
|
||||||
'sender_phone' => '09123456789',
|
|
||||||
'sender_address' => 'Tehran, Valiasr St.',
|
|
||||||
'sender_city' => 'Tehran',
|
|
||||||
'receiver_name' => 'Ali Customer',
|
|
||||||
'receiver_phone' => '+971501234567',
|
|
||||||
'receiver_address' => 'Dubai, Marina',
|
|
||||||
'receiver_city' => 'Dubai',
|
|
||||||
];
|
|
||||||
|
|
||||||
$response4 = Http::withToken($token)
|
|
||||||
->post('http://localhost:8000/api/v1/customer/orders', $orderData);
|
|
||||||
|
|
||||||
echo "Status: " . $response4->status() . "\n";
|
|
||||||
$orderResult = $response4->json();
|
|
||||||
print_r($orderResult);
|
|
||||||
echo "\n";
|
|
||||||
|
|
||||||
// ─── 5. تست لیست سفارشات ───────────────────────────────────
|
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
|
||||||
echo "تست ۵: لیست سفارشات کاربر\n";
|
|
||||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n";
|
|
||||||
|
|
||||||
$response5 = Http::withToken($token)
|
|
||||||
->get('http://localhost:8000/api/v1/customer/orders');
|
|
||||||
|
|
||||||
echo "Status: " . $response5->status() . "\n";
|
|
||||||
$orders = $response5->json();
|
|
||||||
echo "تعداد سفارشات: " . (isset($orders['data']) ? count($orders['data']) : 0) . "\n";
|
|
||||||
if (isset($orders['data']) && count($orders['data']) > 0) {
|
|
||||||
echo "اولین سفارش: AWB = " . ($orders['data'][0]['awb_no'] ?? '—') . "\n";
|
|
||||||
}
|
|
||||||
echo "\n";
|
|
||||||
|
|
||||||
// ─── جمعبندی ───────────────────────────────────────────────
|
|
||||||
echo "══════════════════════════════════════════\n";
|
|
||||||
echo " 🎯 نتیجه نهایی\n";
|
|
||||||
echo "══════════════════════════════════════════\n";
|
|
||||||
echo "Login: " . ($response->status() === 200 ? "✅" : "❌") . "\n";
|
|
||||||
echo "Profile: " . ($response2->status() === 200 ? "✅" : "❌") . "\n";
|
|
||||||
echo "Countries: " . ($response3->status() === 200 ? "✅" : "❌") . "\n";
|
|
||||||
echo "Create Order:" . ($response4->status() === 201 ? "✅" : "❌") . "\n";
|
|
||||||
echo "List Orders: " . ($response5->status() === 200 ? "✅" : "❌") . "\n";
|
|
||||||
echo "══════════════════════════════════════════\n";
|
|
||||||
Loading…
Reference in New Issue
Block a user