Files
boursecu_server/app/Http/Controllers/Pargar/PargarInboundController.php
T

456 lines
15 KiB
PHP
Raw Normal View History

2026-07-05 16:43:34 +03:30
<?php
namespace App\Http\Controllers\Pargar;
use App\Http\Controllers\Controller;
use App\Http\Middleware\PargarAuth;
use App\Models\Cart;
use App\Models\Customer;
use App\Models\Order;
use App\Models\PargarSyncLog;
use App\Models\Product;
use App\Services\ConfigService;
use App\Services\PargarSyncService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Schema;
use Morilog\Jalali\Jalalian;
use Rooyesh\Wallet\interfaces\TransactionInterface;
use Rooyesh\Wallet\interfaces\WalletInterface;
2026-07-05 21:48:11 +03:30
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
2026-07-05 16:43:34 +03:30
class PargarInboundController extends Controller
{
protected function sync(): PargarSyncService
{
return app(PargarSyncService::class);
}
public function login(Request $request)
{
if (! app(ConfigService::class)->isPargarAccounting()) {
return response()->json([
'success' => false,
'data' => null,
'message' => 'Pargar integration is disabled',
], 503);
}
2026-07-10 16:23:42 +03:30
[$username, $password] = $this->pargarLoginCredentials($request);
2026-07-05 16:43:34 +03:30
2026-07-10 16:23:42 +03:30
$expectedUser = $this->normalizeCredential(trim((string) $this->Config('pargar_username')));
$expectedPass = $this->normalizeCredential(trim((string) $this->Config('pargar_password')));
2026-07-05 16:43:34 +03:30
if ($username !== $expectedUser || $password !== $expectedPass || $expectedUser === '') {
return response()->json([
'success' => false,
'data' => null,
'message' => 'Invalid credentials!',
]);
}
$token = PargarAuth::issueToken($username);
return response()->json([
'success' => true,
'data' => ['token' => $token],
'message' => 'You are logged in successfully.',
]);
}
public function upsertCustomers(Request $request)
{
2026-07-10 16:37:58 +03:30
$payload = $this->pargarPayload($request);
$customers = $payload['Customers'] ?? [];
2026-07-05 16:43:34 +03:30
if (! is_array($customers) || $customers === []) {
return response()->json([
'success' => false,
'message' => 'Customers list is required',
'data' => null,
], 422);
}
$messages = [];
foreach ($customers as $row) {
if (! is_array($row)) {
continue;
}
$accountId = trim((string) ($row['AccountId'] ?? ''));
$fullName = trim((string) ($row['FullName'] ?? ''));
2026-07-05 21:48:11 +03:30
$mobile = Customer::normalizeMobile((string) ($row['CellPhone'] ?? ''));
2026-07-05 16:43:34 +03:30
2026-07-05 21:48:11 +03:30
if ($accountId === '' || $mobile === null) {
2026-07-05 16:43:34 +03:30
$messages[] = 'ردیف نامعتبر: AccountId یا CellPhone خالی است';
continue;
}
2026-07-05 21:48:11 +03:30
$byAccount = Customer::whereNull('deleted_at')
->where('pargar_account_id', $accountId)
2026-07-05 16:43:34 +03:30
->first();
2026-07-05 21:48:11 +03:30
if ($byAccount && Customer::normalizeMobile($byAccount->mobile) !== $mobile) {
$messages[] = "کد حساب {$accountId} قبلاً برای مشتری دیگری ثبت شده است";
continue;
}
$customer = Customer::findActiveByMobile($mobile);
2026-07-05 16:43:34 +03:30
if ($customer) {
2026-07-05 21:48:11 +03:30
$currentAccount = (string) ($customer->pargar_account_id ?? '');
if ($currentAccount === $accountId) {
2026-07-05 16:43:34 +03:30
$messages[] = 'کد حساب مشتری وجود دارد';
continue;
}
2026-07-05 21:48:11 +03:30
if ($currentAccount !== '' && $currentAccount !== $accountId) {
$messages[] = "شماره {$mobile} قبلاً به حساب پرگار دیگری متصل است";
continue;
}
2026-07-05 16:43:34 +03:30
$customer->pargar_account_id = $accountId;
if ($fullName !== '') {
$customer->fname = $fullName;
$customer->name = $fullName;
}
$customer->save();
$messages[] = "کد حسابداری مشتری {$fullName} ویرایش شد";
continue;
}
2026-07-05 21:48:11 +03:30
if ($byAccount) {
if (Customer::isMobileTaken($mobile, (int) $byAccount->id)) {
$messages[] = "شماره {$mobile} تکراری است";
continue;
}
2026-07-05 16:43:34 +03:30
2026-07-05 21:48:11 +03:30
if ($fullName !== '') {
$byAccount->fname = $fullName;
$byAccount->name = $fullName;
}
$byAccount->mobile = $mobile;
if (empty($byAccount->password)) {
$byAccount->password = $mobile;
}
$byAccount->save();
$messages[] = "مشتری با کد حسابداری {$accountId} به‌روزرسانی شد";
continue;
}
try {
$customer = new Customer();
$customer->fname = $fullName !== '' ? $fullName : 'مشتری';
$customer->name = $customer->fname;
$customer->mobile = $mobile;
$customer->pargar_account_id = $accountId;
$customer->active = true;
$customer->type = 2;
$customer->password = $mobile;
$customer->referral_id = $this->uniqueReferralId();
$customer->save();
$messages[] = "مشتری با کد حسابداری {$accountId} ایجاد شد";
} catch (\Throwable $e) {
$messages[] = "خطا برای {$mobile}: " . (
$e instanceof UnprocessableEntityHttpException
? $e->getMessage()
: 'ثبت مشتری ناموفق بود'
);
}
2026-07-05 16:43:34 +03:30
}
return response()->json([
'success' => true,
'message' => implode(' | ', $messages),
'data' => null,
]);
}
public function listOrders(Request $request)
{
$orders = Order::query()
->where('sts', 2)
->whereNull('pargar_confirmed_at')
->limit(100)
->get();
$documents = $orders->map(function (Order $order) {
$customer = Customer::find((int) ($order->customer_id ?? 0));
return [
'OrderId' => (string) $order->id,
'OrderType' => (int) ($order->direction ?? 1) === 1 ? 1 : -1,
'PriceType' => 1,
'CustomerAccountId' => (int) ($customer->pargar_account_id ?? 0),
'ItemId' => 11,
'ItemName' => $this->pargarItemName($order),
'OrderDate' => $order->pay_at
? Jalalian::fromDateTime($order->pay_at)->format('Y/m/d-H:i:s')
: Jalalian::fromDateTime($order->created_at)->format('Y/m/d-H:i:s'),
'Fee' => (float) ($order->price ?? 0),
'Count' => 1,
'Weight' => (float) ($order->amount ?? 0),
'Price' => (float) ($order->total_price ?? 0),
'Carat' => 750,
'Description' => (string) ($order->description ?? ''),
];
})->values();
return response()->json([
'state' => 'true',
'msg' => '',
'data' => [
'documents' => $documents,
'duplicated' => 'false',
'result' => 'OK',
],
]);
}
public function confirmOrders(Request $request)
{
2026-07-10 16:37:58 +03:30
$payload = $this->pargarPayload($request);
$orderIds = $payload['OrderIds'] ?? [];
2026-07-05 16:43:34 +03:30
if (! is_array($orderIds)) {
return response()->json([
'success' => false,
'message' => 'OrderIds must be an array',
'data' => null,
], 422);
}
$this->sync()->confirmOrders($orderIds);
return response()->json([
'success' => true,
'message' => 'تاییدیه اسناد با موفقیت دریافت شد',
'data' => null,
]);
}
public function storeDocuments(Request $request)
{
2026-07-10 16:37:58 +03:30
$data = $this->pargarPayload($request);
2026-07-05 16:43:34 +03:30
$accountId = trim((string) ($data['accountId'] ?? ''));
$transactions = $data['transactions'] ?? [];
$customer = $accountId !== ''
? Customer::where('pargar_account_id', $accountId)->first()
: null;
PargarSyncLog::create([
'customer_id' => $customer?->id,
'desc' => 'دریافت اسناد از پرگار',
'type' => 'document',
'sync_status' => PargarSyncService::STATUS_SUCCESS,
'pargar_ref' => $accountId,
'data' => json_encode($data, JSON_UNESCAPED_UNICODE),
]);
return response()->json([
'success' => true,
'message' => 'اسناد مشتری با موفقیت دریافت شد',
'data' => null,
]);
}
public function storeMande(Request $request)
{
2026-07-10 16:37:58 +03:30
$data = $this->pargarPayload($request);
2026-07-05 16:43:34 +03:30
$accountId = trim((string) ($data['AccountId'] ?? ''));
$customer = Customer::where('pargar_account_id', $accountId)->first();
if (! $customer) {
return response()->json([
'success' => false,
'message' => 'مشتری یافت نشد',
'data' => null,
], 422);
}
$goldInv = isset($data['GoldInv']) ? (float) str_replace('/', '.', (string) $data['GoldInv']) : 0;
$rialInv = isset($data['RialInv']) ? (float) str_replace('/', '.', (string) $data['RialInv']) : 0;
$wallet = $customer->wallet->where('fund_id', null)->first();
if ($wallet) {
$goldDiff = $goldInv - (float) $wallet->gold;
$rialDiff = $rialInv - (float) $wallet->cash;
} else {
$goldDiff = $goldInv;
$rialDiff = $rialInv;
}
if (abs($goldDiff) >= 0.01 || abs($rialDiff) >= 1) {
$walletInterface = new WalletInterface($customer->id, 2);
new TransactionInterface($walletInterface, [
'cash' => $rialDiff,
'gold' => $goldDiff,
'expire_at' => now(),
'active' => true,
'start_at' => now(),
], 22, $goldDiff > 0, $rialDiff > 0);
}
PargarSyncLog::create([
'customer_id' => $customer->id,
'desc' => 'دریافت مانده از پرگار',
'type' => 'mande',
'amount' => $goldInv,
'sync_status' => PargarSyncService::STATUS_SUCCESS,
'pargar_ref' => $accountId,
'data' => json_encode($data, JSON_UNESCAPED_UNICODE),
]);
return response()->json([
'success' => true,
'message' => 'مانده مشتری با موفقیت دریافت شد',
'data' => null,
]);
}
public function listNewCustomers(Request $request)
{
$customers = Customer::query()
->whereNull('deleted_at')
->whereNull('pargar_account_id')
->limit(100)
->get(['id', 'fname', 'lname', 'mobile']);
if ($customers->isEmpty()) {
return response()->json([
'success' => true,
'message' => 'مشتری جدید وجود ندارد',
'data' => null,
]);
}
$rows = $customers->map(function (Customer $customer) {
$nameParts = preg_split('/\s+/', trim((string) $customer->name), 2) ?: ['', ''];
return [
'id' => (string) $customer->id,
'name' => $nameParts[0] ?? '',
'family' => $nameParts[1] ?? '',
'mobile' => (string) $customer->mobile,
];
});
return response()->json([
'state' => 'true',
'msg' => '',
'customer' => $rows,
]);
}
public function confirmCustomers(Request $request)
{
2026-07-10 16:37:58 +03:30
$payload = $this->pargarPayload($request);
$rows = $payload['customers'] ?? [];
2026-07-05 16:43:34 +03:30
if (! is_array($rows)) {
return response()->json([
'success' => false,
'message' => 'customers must be an array',
'data' => null,
], 422);
}
foreach ($rows as $row) {
if (! is_array($row)) {
continue;
}
$customerId = $row['customer_id'] ?? $row['id_customer'] ?? null;
$accountId = $row['accounting_id'] ?? null;
if ($customerId === null || $accountId === null) {
continue;
}
$customer = Customer::find($customerId);
if ($customer) {
$customer->pargar_account_id = (string) $accountId;
$customer->save();
$log = PargarSyncLog::query()
->where('customer_id', $customer->id)
->where('type', 'customer')
->where('sync_status', PargarSyncService::STATUS_PENDING)
->latest('id')
->first();
if ($log) {
$this->sync()->markSuccess($log, (string) $accountId);
}
}
}
return response()->json([
'success' => true,
'message' => 'تاییدیه ثبت مشتری با موفقیت دریافت شد',
'data' => null,
]);
}
2026-07-10 16:23:42 +03:30
/**
* @return array{0: string, 1: string}
*/
private function pargarLoginCredentials(Request $request): array
{
2026-07-10 16:37:58 +03:30
$payload = $this->pargarPayload($request);
2026-07-10 16:23:42 +03:30
return [
2026-07-10 16:37:58 +03:30
$this->normalizeCredential((string) ($payload['username'] ?? '')),
$this->normalizeCredential((string) ($payload['password'] ?? '')),
2026-07-10 16:23:42 +03:30
];
}
2026-07-10 16:37:58 +03:30
/**
* @return array<string, mixed>
*/
private function pargarPayload(Request $request): array
{
$payload = $request->all();
if ($payload !== []) {
return $payload;
}
$decoded = json_decode((string) $request->getContent(), true);
return is_array($decoded) ? $decoded : [];
}
2026-07-10 16:23:42 +03:30
private function normalizeCredential(string $value): string
{
$persian = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
$arabic = ['٠', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩'];
$latin = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
return trim(str_replace(array_merge($persian, $arabic), array_merge($latin, $latin), $value));
}
2026-07-05 16:43:34 +03:30
private function uniqueReferralId(): string
{
do {
$referral = substr(str_shuffle('0123456789abcdefghijklmnopqrstuvwxyz'), 0, 4);
} while (Customer::where('referral_id', $referral)->exists());
return $referral;
}
private function pargarItemName(Order $order): string
{
return $this->isCartOrder($order) ? 'سبد خرید' : 'آبشده';
}
private function isCartOrder(Order $order): bool
{
if (Schema::hasTable('cart') && Schema::hasColumn('cart', 'order_id')) {
return Cart::where('order_id', $order->id)->exists();
}
return PargarSyncLog::where('order_id', $order->id)
->where('desc', 'سبد خرید')
->exists();
}
}