Files
boursecu_server/app/Http/Controllers/Admin/PargarController.php
T
2026-07-21 14:13:26 +03:30

310 lines
10 KiB
PHP

<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Customer;
use App\Models\PargarSyncLog;
use App\Services\ConfigService;
use App\Services\PargarInboundWalletService;
use App\Services\PargarSyncService;
use Illuminate\Http\Request;
class PargarController extends Controller
{
protected function sync(): PargarSyncService
{
return app(PargarSyncService::class);
}
public function table(Request $request)
{
$query = PargarSyncLog::with('customer')->orderByDesc('id');
\App\DB\Te\TableEngine::create($query, $request)
->initSearch(['desc', 'type'])
->select(['*'])
->export($query);
return response()->json($query);
}
public function show($id)
{
return response()->json(PargarSyncLog::with('customer')->findOrFail($id));
}
public function customerSyncStatus(Request $request)
{
$panelTotal = Customer::whereNull('deleted_at')->count();
$panelRegistered = Customer::whereNull('deleted_at')->whereNotNull('pargar_account_id')->count();
$panelOnly = $panelTotal - $panelRegistered;
$panelOnlyQuery = Customer::whereNull('deleted_at')
->whereNull('pargar_account_id')
->select('id', 'name', 'mobile', 'created_at');
if ($search = $request->input('search')) {
$panelOnlyQuery->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('mobile', 'like', "%{$search}%");
});
}
$panelOnlyList = $panelOnlyQuery->orderBy('id')->paginate(20);
$inboundOnlyQuery = PargarSyncLog::query()
->where('type', 'customer')
->where('sync_status', PargarSyncService::STATUS_SUCCESS)
->whereNotNull('pargar_ref')
->latest('id');
$inboundOnlyCount = (clone $inboundOnlyQuery)->count();
$inboundSample = $inboundOnlyQuery->limit(100)->get(['id', 'customer_id', 'pargar_ref', 'created_at']);
return response()->json([
'panel_total' => $panelTotal,
'panel_registered' => $panelRegistered,
'panel_only' => $panelOnly,
'pargar_total' => $panelRegistered + $inboundOnlyCount,
'pargar_only_count' => max(0, $inboundOnlyCount),
'panel_only_list' => $panelOnlyList,
'pargar_only_list' => [
'data' => $inboundSample->map(fn ($row) => [
'code' => $row->pargar_ref,
'name' => $row->customer?->name ?? '',
'tel' => $row->customer?->mobile ?? '',
'gid' => null,
'group' => '',
])->values(),
'total' => $inboundOnlyCount,
'current_page' => 1,
'last_page' => 1,
],
]);
}
public function syncPanelToPargar()
{
$customers = Customer::whereNull('deleted_at')
->whereNull('pargar_account_id')
->get(['id', 'name', 'mobile']);
$success = 0;
$failed = 0;
$errors = [];
foreach ($customers as $customer) {
$result = $this->sync()->registerCustomer($customer);
if ($result['ok'] ?? false) {
$success++;
} else {
$failed++;
$errors[] = [
'name' => $customer->name,
'mobile' => $customer->mobile,
'error' => $result['message'] ?? '',
];
}
}
return response()->json([
'ok' => true,
'success' => $success,
'failed' => $failed,
'errors' => $errors,
]);
}
public function importFromPargar(Request $request)
{
$validated = $request->validate([
'customers' => 'required|array',
'customers.*.code' => 'required',
'customers.*.name' => 'required|string',
'customers.*.tel' => 'nullable|string',
]);
$success = 0;
$failed = 0;
$errors = [];
foreach ($validated['customers'] as $item) {
$mobile = Customer::normalizeMobile($item['tel'] ?? '') ?? '';
$fullName = trim($item['name']);
$accountId = (string) $item['code'];
$existing = Customer::whereNull('deleted_at')
->where('pargar_account_id', $accountId)
->first();
if ($existing) {
$success++;
continue;
}
if ($mobile !== '') {
$byMobile = Customer::findActiveByMobile($mobile);
if ($byMobile) {
$currentAccount = (string) ($byMobile->pargar_account_id ?? '');
if ($currentAccount !== '' && $currentAccount !== $accountId) {
$failed++;
$errors[] = [
'name' => $item['name'],
'code' => $item['code'],
'error' => 'شماره موبایل تکراری است',
];
continue;
}
$byMobile->pargar_account_id = $accountId;
if ($fullName !== '') {
$byMobile->fname = $fullName;
$byMobile->name = $fullName;
}
$byMobile->save();
$success++;
continue;
}
}
$byAccount = Customer::whereNull('deleted_at')
->where('pargar_account_id', $accountId)
->first();
if ($byAccount) {
$failed++;
$errors[] = [
'name' => $item['name'],
'code' => $item['code'],
'error' => 'کد حساب پرگار قبلاً ثبت شده است',
];
continue;
}
try {
$customer = new Customer();
$customer->fname = $fullName;
$customer->lname = '';
$customer->name = $fullName;
$customer->mobile = $mobile;
$customer->active = true;
$customer->pargar_account_id = $accountId;
$customer->referral_id = $this->uniqueReferralId();
$customer->type = 2;
if ($mobile !== '') {
$customer->password = $mobile;
}
$customer->save();
$success++;
} catch (\Throwable $e) {
$failed++;
$errors[] = ['name' => $item['name'], 'code' => $item['code'], 'error' => $e->getMessage()];
}
}
return response()->json([
'ok' => true,
'success' => $success,
'failed' => $failed,
'errors' => $errors,
]);
}
public function rollbackImport(Request $request)
{
$baseQuery = fn () => Customer::whereNotNull('pargar_account_id')
->where(function ($q) {
$q->whereNull('name')->orWhere('name', '');
});
$count = $baseQuery()->count();
$sample = $baseQuery()
->select('id', 'fname', 'name', 'mobile', 'pargar_account_id', 'created_at')
->orderByDesc('id')
->limit(20)
->get();
if ($request->boolean('dry_run')) {
return response()->json([
'dry_run' => true,
'count' => $count,
'sample' => $sample,
]);
}
$deleted = $baseQuery()->forceDelete();
return response()->json([
'ok' => true,
'deleted' => $deleted,
]);
}
public function retrySanad($id)
{
$log = PargarSyncLog::with('customer')->findOrFail($id);
$result = $this->sync()->retry($log);
return response()->json($result, ($result['ok'] ?? false) ? 200 : 422);
}
public function registerCustomer($customerId)
{
$customer = Customer::findOrFail($customerId);
$result = $this->sync()->registerCustomer($customer);
return response()->json($result, ($result['ok'] ?? false) ? 200 : 422);
}
public function syncCustomerWallet(Request $request, $customerId)
{
if (! app(ConfigService::class)->isPargarAccounting()) {
return response()->json([
'ok' => false,
'message' => 'حسابداری پرگار فعال نیست',
], 422);
}
$customer = Customer::findOrFail($customerId);
if (trim((string) ($customer->pargar_account_id ?? '')) === '') {
return response()->json([
'ok' => false,
'message' => 'این مشتری کد حساب پرگار ندارد',
], 422);
}
$force = $request->boolean('force');
$result = app(PargarInboundWalletService::class)->syncWalletFromPargar($customer, $force);
$appliedDocs = (int) ($result['documents']['applied'] ?? 0);
$appliedMande = (bool) ($result['mande']['applied'] ?? false);
$mandeMessage = (string) ($result['mande']['message'] ?? '');
$ok = $appliedDocs > 0 || $appliedMande;
if ($appliedDocs > 0 && $appliedMande) {
$message = "{$appliedDocs} سند و ماندهٔ پرگار روی کیف اعمال شد";
} elseif ($appliedDocs > 0) {
$message = "{$appliedDocs} سند از پرگار روی کیف اعمال شد";
} elseif ($appliedMande) {
$message = 'ماندهٔ پرگار روی کیف اعمال شد';
} else {
$message = $mandeMessage !== ''
? $mandeMessage
: 'سند قابل‌اعمالی یافت نشد';
}
return response()->json([
'ok' => $ok,
'message' => $message,
'result' => $result,
]);
}
private function uniqueReferralId(): string
{
do {
$referral = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyz'), 0, 4);
} while (Customer::where('referral_id', $referral)->exists());
return $referral;
}
}