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

735 lines
28 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\Services\ConfigService;
2026-07-21 12:36:59 +03:30
use App\Services\PargarInboundWalletService;
2026-07-05 16:43:34 +03:30
use App\Services\PargarSyncService;
2026-07-25 12:02:58 +03:30
use App\Services\WalletBalanceService;
2026-07-05 16:43:34 +03:30
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Schema;
use Morilog\Jalali\Jalalian;
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;
2026-07-10 17:01:57 +03:30
$this->applyPargarCustomerName($customer, $fullName);
2026-07-05 16:43:34 +03:30
$customer->save();
2026-07-22 00:31:38 +03:30
app(PargarInboundWalletService::class)->queueWalletSyncAfterResponse((int) $customer->id);
2026-07-05 16:43:34 +03:30
$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 !== '') {
2026-07-10 17:01:57 +03:30
$this->applyPargarCustomerName($byAccount, $fullName);
2026-07-05 21:48:11 +03:30
}
$byAccount->mobile = $mobile;
if (empty($byAccount->password)) {
$byAccount->password = $mobile;
}
$byAccount->save();
2026-07-22 00:31:38 +03:30
app(PargarInboundWalletService::class)->queueWalletSyncAfterResponse((int) $byAccount->id);
2026-07-05 21:48:11 +03:30
$messages[] = "مشتری با کد حسابداری {$accountId} به‌روزرسانی شد";
continue;
}
try {
$customer = new Customer();
2026-07-10 17:01:57 +03:30
$this->applyPargarCustomerName($customer, $fullName !== '' ? $fullName : 'مشتری');
2026-07-05 21:48:11 +03:30
$customer->mobile = $mobile;
$customer->pargar_account_id = $accountId;
$customer->active = true;
$customer->type = 2;
$customer->password = $mobile;
$customer->referral_id = $this->uniqueReferralId();
$customer->save();
2026-07-22 00:31:38 +03:30
app(PargarInboundWalletService::class)->queueWalletSyncAfterResponse((int) $customer->id);
2026-07-05 21:48:11 +03:30
$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)
{
2026-07-20 15:52:42 +03:30
$documents = collect();
2026-07-05 16:43:34 +03:30
$orders = Order::query()
->where('sts', 2)
->whereNull('pargar_confirmed_at')
->limit(100)
->get();
2026-07-20 15:52:42 +03:30
foreach ($orders as $order) {
$payload = $this->orderExportPayload($order);
if ($payload === null) {
continue;
}
$documents->push($payload);
}
2026-07-05 16:43:34 +03:30
2026-07-20 15:52:42 +03:30
$walletLogs = PargarSyncLog::query()
->whereIn('type', [PargarSyncService::TYPE_WALLET_CASH, PargarSyncService::TYPE_WALLET_GOLD])
->where('sync_status', PargarSyncService::STATUS_PENDING)
->orderBy('id')
->limit(100)
->get();
2026-07-18 12:37:29 +03:30
2026-07-20 15:52:42 +03:30
foreach ($walletLogs as $log) {
$payload = $this->walletExportPayload($log);
if ($payload !== null) {
$documents->push($payload);
}
}
2026-07-05 16:43:34 +03:30
return response()->json([
'state' => 'true',
'msg' => '',
'data' => [
2026-07-20 15:52:42 +03:30
'documents' => $documents->values(),
2026-07-05 16:43:34 +03:30
'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);
}
2026-07-22 01:05:00 +03:30
$result = $this->sync()->confirmOrders($orderIds);
// سند در پرگار ثبت شد → ماندهٔ معطل‌مانده را همگام کن
foreach ($result['customer_ids'] ?? [] as $customerId) {
$this->inboundWallet()->queueWalletSyncAfterResponse((int) $customerId);
}
2026-07-05 16:43:34 +03:30
return response()->json([
'success' => true,
'message' => 'تاییدیه اسناد با موفقیت دریافت شد',
'data' => null,
]);
}
2026-07-21 12:36:59 +03:30
protected function inboundWallet(): PargarInboundWalletService
{
return app(PargarInboundWalletService::class);
}
2026-07-05 16:43:34 +03:30
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'] ?? ''));
2026-07-21 14:16:27 +03:30
$summary = $this->sync()->summarizeInboundDocument($data);
2026-07-05 16:43:34 +03:30
$customer = $accountId !== ''
? Customer::where('pargar_account_id', $accountId)->first()
: null;
2026-07-22 01:05:00 +03:30
// فقط لاگ — replay تاریخچه روی کیف خاموش است؛ بعد از ذخیره، مانده به‌صورت خودکار هم‌تراز می‌شود
2026-07-05 16:43:34 +03:30
PargarSyncLog::create([
2026-07-21 14:16:27 +03:30
'customer_id' => $customer?->id,
2026-07-21 12:36:59 +03:30
'amount' => $summary['amount'],
2026-07-21 14:16:27 +03:30
'desc' => $customer
2026-07-22 01:05:00 +03:30
? ($summary['desc'] !== '' ? $summary['desc'] : 'دریافت اسناد از پرگار')
: 'دریافت اسناد از پرگار — مشتری یافت نشد',
2026-07-20 15:52:42 +03:30
'type' => PargarSyncService::TYPE_DOCUMENT,
2026-07-05 16:43:34 +03:30
'sync_status' => PargarSyncService::STATUS_SUCCESS,
2026-07-21 12:36:59 +03:30
'pargar_ref' => $accountId !== '' ? $accountId : null,
'data' => json_encode(array_merge($data, [
'_summary' => $summary,
'wallet_applied' => false,
2026-07-22 01:05:00 +03:30
'code_build' => 'docs-then-mande-auto',
2026-07-21 12:36:59 +03:30
]), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT),
2026-07-05 16:43:34 +03:30
]);
2026-07-22 01:05:00 +03:30
\Illuminate\Support\Facades\Log::info('Pargar documents stored; queue auto mande sync', [
2026-07-21 14:23:26 +03:30
'account_id' => $accountId,
'customer_id' => $customer?->id,
'tx_count' => is_array($data['transactions'] ?? null) ? count($data['transactions']) : 0,
]);
2026-07-22 01:05:00 +03:30
// به‌محض ورود اسناد → ack + اعمال آخرین مانده
if ($customer) {
$this->inboundWallet()->queueWalletSyncAfterResponse((int) $customer->id);
}
2026-07-05 16:43:34 +03:30
return response()->json([
'success' => true,
2026-07-22 01:05:00 +03:30
'message' => 'اسناد ثبت شد؛ همگام‌سازی مانده در صف است',
2026-07-21 14:23:26 +03:30
'data' => [
'wallet_applied' => false,
2026-07-22 01:05:00 +03:30
'auto_mande_queued' => (bool) $customer,
'build' => 'docs-then-mande-auto',
2026-07-21 14:23:26 +03:30
],
2026-07-05 16:43:34 +03:30
]);
}
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();
$goldInv = isset($data['GoldInv']) ? (float) str_replace('/', '.', (string) $data['GoldInv']) : 0;
$rialInv = isset($data['RialInv']) ? (float) str_replace('/', '.', (string) $data['RialInv']) : 0;
2026-07-22 00:31:38 +03:30
if (! $customer) {
PargarSyncLog::create([
'customer_id' => null,
'desc' => 'مانده پرگار — مشتری هنوز در پنل نیست',
'type' => PargarSyncService::TYPE_MANDE,
'amount' => $goldInv,
'sync_status' => PargarSyncService::STATUS_SUCCESS,
'pargar_ref' => $accountId,
'data' => json_encode(array_merge($data, [
'orphan_mande' => true,
'wallet_adjusted' => false,
]), JSON_UNESCAPED_UNICODE),
]);
return response()->json([
'success' => true,
'message' => 'مانده ذخیره شد؛ پس از ثبت مشتری اعمال می‌شود',
'data' => null,
]);
}
2026-07-18 15:30:59 +03:30
$ownerType = (int) ($customer->type ?? 2);
$walletInterface = new WalletInterface($customer->id, $ownerType);
$wallet = $walletInterface->wallet;
2026-07-25 12:02:58 +03:30
// GoldInv پرگار فقط با طلای کیف اصلی مقایسه می‌شود — محصولات جدا سهمی ندارند
$appGold = app(WalletBalanceService::class)
->effectiveMainWalletGold((int) $customer->id, $ownerType);
2026-07-20 15:52:42 +03:30
$appCash = (float) ($wallet->cash ?? 0);
$goldDiff = $goldInv - $appGold;
$rialDiff = $rialInv - $appCash;
$hasDiff = abs($goldDiff) >= 0.01 || abs($rialDiff) >= 1;
2026-07-05 16:43:34 +03:30
2026-07-22 01:05:00 +03:30
$pendingOutbound = $this->inboundWallet()->hasPendingOutboundToPargar($customer);
$desc = $pendingOutbound
? 'مانده دریافت شد — منتظر ثبت سند پنل در پرگار'
: ($hasDiff
2026-07-25 12:02:58 +03:30
? 'اختلاف مانده پرگار با اپ — پس از تأیید پایداری اعمال می‌شود'
2026-07-22 01:05:00 +03:30
: 'دریافت مانده از پرگار — بدون اختلاف');
2026-07-05 16:43:34 +03:30
PargarSyncLog::create([
'customer_id' => $customer->id,
2026-07-20 15:52:42 +03:30
'desc' => $desc,
'type' => PargarSyncService::TYPE_MANDE,
2026-07-05 16:43:34 +03:30
'amount' => $goldInv,
'sync_status' => PargarSyncService::STATUS_SUCCESS,
'pargar_ref' => $accountId,
2026-07-20 15:52:42 +03:30
'data' => json_encode(array_merge($data, [
'app_gold' => $appGold,
'app_cash' => $appCash,
'gold_diff' => $goldDiff,
'rial_diff' => $rialDiff,
'wallet_adjusted' => false,
2026-07-22 01:05:00 +03:30
'awaiting_outbound_confirm' => $pendingOutbound,
2026-07-20 15:52:42 +03:30
]), JSON_UNESCAPED_UNICODE),
2026-07-05 16:43:34 +03:30
]);
2026-07-22 01:05:00 +03:30
// همیشه صف همگام‌سازی: اگر سند pending نباشد اعمال می‌شود؛ وگرنه بعد از تأیید سند اعمال می‌شود
$this->inboundWallet()->queueWalletSyncAfterResponse((int) $customer->id);
2026-07-22 00:31:38 +03:30
2026-07-05 16:43:34 +03:30
return response()->json([
'success' => true,
2026-07-22 01:05:00 +03:30
'message' => $pendingOutbound
? 'مانده ذخیره شد؛ بعد از ثبت سند در پرگار خودکار سینک می‌شود'
: 'مانده دریافت شد؛ همگام‌سازی خودکار در صف است',
'data' => [
'awaiting_outbound_confirm' => $pendingOutbound,
'auto_sync_queued' => true,
],
2026-07-05 16:43:34 +03:30
]);
}
public function listNewCustomers(Request $request)
{
$customers = Customer::query()
->whereNull('deleted_at')
->where(function ($q) {
$q->whereNull('pargar_account_id')
->orWhere('pargar_account_id', '')
->orWhere('pargar_account_id', '0')
->orWhere('pargar_account_id', '-1');
})
2026-07-05 16:43:34 +03:30
->limit(100)
2026-07-10 17:01:57 +03:30
->get(['id', 'fname', 'lname', 'name', 'mobile']);
2026-07-05 16:43:34 +03:30
if ($customers->isEmpty()) {
return response()->json([
'success' => true,
'message' => 'مشتری جدید وجود ندارد',
'data' => null,
]);
}
$rows = $customers->map(function (Customer $customer) {
2026-07-10 17:01:57 +03:30
$fname = trim((string) ($customer->fname ?? ''));
$lname = trim((string) ($customer->lname ?? ''));
if ($fname === '' && $lname === '') {
$nameParts = preg_split('/\s+/', trim((string) ($customer->name ?? '')), 2) ?: ['', ''];
$fname = trim((string) ($nameParts[0] ?? ''));
$lname = trim((string) ($nameParts[1] ?? ''));
}
2026-07-05 16:43:34 +03:30
return [
'id' => (string) $customer->id,
2026-07-10 17:01:57 +03:30
'name' => $fname,
'family' => $lname,
2026-07-05 16:43:34 +03:30
'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;
}
$normalizedAccountId = trim((string) $accountId);
if ($normalizedAccountId === '' || in_array($normalizedAccountId, ['0', '-1'], true)) {
continue;
}
2026-07-05 16:43:34 +03:30
$customer = Customer::find($customerId);
if ($customer) {
$customer->pargar_account_id = $normalizedAccountId;
2026-07-05 16:43:34 +03:30
$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, $normalizedAccountId);
2026-07-05 16:43:34 +03:30
}
2026-07-22 00:31:38 +03:30
app(PargarInboundWalletService::class)->queueWalletSyncAfterResponse((int) $customer->id);
2026-07-05 16:43:34 +03:30
}
}
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-10 17:01:57 +03:30
private function applyPargarCustomerName(Customer $customer, string $fullName): void
{
$fullName = trim($fullName);
if ($fullName === '') {
return;
}
[$fname, $lname] = $this->splitPargarFullName($fullName);
$customer->fname = $fname;
$customer->lname = $lname;
// mutator مدل Customer مقدار name را از fname + lname می‌سازد
$customer->name = trim("$fname $lname");
}
/**
* @return array{0: string, 1: string}
*/
private function splitPargarFullName(string $fullName): array
{
$parts = preg_split('/\s+/u', trim($fullName), 2) ?: ['', ''];
return [
trim((string) ($parts[0] ?? '')),
trim((string) ($parts[1] ?? '')),
];
}
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)
2026-07-18 16:38:46 +03:30
->whereIn('desc', ['سبد خرید', 'فروش سبد به مشتری'])
2026-07-05 16:43:34 +03:30
->exists();
}
2026-07-20 15:52:42 +03:30
/**
* @return array<string, mixed>|null
*/
private function orderExportPayload(Order $order): ?array
{
$sync = $this->sync();
$log = PargarSyncLog::where('order_id', $order->id)->latest('id')->first();
$payload = $log ? (json_decode((string) $log->data, true) ?: []) : [];
$paymentKind = (string) ($payload['payment_kind'] ?? PargarSyncService::PAYMENT_CASH);
if ($paymentKind === PargarSyncService::PAYMENT_OTHER_PRODUCT) {
return null;
}
if ($log && is_string($log->pargar_ref) && str_starts_with($log->pargar_ref, 'skip:')) {
return null;
}
$customer = Customer::find((int) ($order->customer_id ?? 0));
$isCustomerBuy = (int) ($order->direction ?? 1) === 1;
$customerDirection = (int) ($order->direction ?? 0);
$fromCart = (bool) ($payload['from_cart'] ?? $this->isCartOrder($order));
$product = $sync->resolveOrderProduct($order, $payload);
$number = (float) ($payload['number'] ?? 0);
2026-07-20 19:11:04 +03:30
$amount = abs((float) ($order->amount ?? 0));
2026-07-20 15:52:42 +03:30
$totalPrice = (float) ($order->total_price ?? $order->payment_amount ?? 0);
$unitPrice = (float) ($order->price ?? 0);
$isCountBased = $product
? self::isCountBasedProduct(self::productUnitPayload($product))
: false;
2026-07-20 19:11:04 +03:30
// پرگار: Count>0 → سند تعدادی (وزن را نادیده می‌گیرد)
// آبشده/وزنی مثل آذین: Count=0 و Weight=گرم
$count = 0;
2026-07-20 15:52:42 +03:30
$weight = $amount;
2026-07-20 19:11:04 +03:30
if ($isCountBased) {
$count = $number > 0 ? max(1, (int) round($number)) : 1;
2026-07-20 15:52:42 +03:30
$weight = $amount;
}
$itemId = $sync->pargarItemIdGold();
$itemName = $this->pargarItemName($order);
if ($product && trim((string) $product->title) !== '') {
$itemName = trim((string) $product->title);
}
$tradedProductId = (int) ($payload['product_id'] ?? $order->product_id ?? 0);
2026-07-21 22:23:09 +03:30
// فقط محصولات main_wallet_products روی GoldInv آبشده اثر دارند.
// group_type=آبشده به‌تنهایی کافی نیست (مثلاً آبشده سرمایه‌گذاری / قلک).
if ($tradedProductId > 0) {
$tradesMainGold = app(ConfigService::class)->isMainWalletProduct($tradedProductId);
} else {
$tradesMainGold = $product && self::isMeltedTradeGroup($product->group_type ?? null);
}
2026-07-20 15:52:42 +03:30
2026-07-21 22:23:09 +03:30
// اثر مانده از روش پرداخت؛ وزن طلا فقط وقتی کالای معامله به کیف اصلی مربوط است
2026-07-20 15:52:42 +03:30
if ($paymentKind === PargarSyncService::PAYMENT_CASH) {
if ($tradesMainGold) {
2026-07-20 19:11:04 +03:30
// خرید/فروش آبشده کیف‌اصلی با نقدی: وزن + مبلغ — حتماً تعدادی نباشد
2026-07-20 15:52:42 +03:30
$itemId = $sync->pargarItemIdGold();
2026-07-20 19:11:04 +03:30
$count = 0;
$weight = $amount;
2026-07-20 15:52:42 +03:30
} else {
2026-07-21 22:23:09 +03:30
// محصول غیر اصلی با پرداخت نقدی: فقط ریال (بدون وزن طلای پرگار)
2026-07-20 15:52:42 +03:30
$rialItemId = $sync->pargarItemIdRial();
$itemId = $rialItemId > 0 ? $rialItemId : $sync->pargarItemIdGold();
$weight = 0;
2026-07-20 19:11:04 +03:30
$count = 0;
2026-07-20 15:52:42 +03:30
}
} elseif ($paymentKind === PargarSyncService::PAYMENT_MAIN_GOLD) {
$itemId = $sync->pargarItemIdGold();
$itemName = $sync->mainWalletGoldItemName();
2026-07-20 19:11:04 +03:30
$paymentGold = abs((float) ($payload['payment_gold'] ?? $amount));
$weight = $paymentGold;
$count = 0;
2026-07-20 15:52:42 +03:30
$totalPrice = 0;
}
return [
'OrderId' => (string) $order->id,
'OrderType' => $isCustomerBuy ? -1 : 1,
'PriceType' => 1,
'CustomerAccountId' => (int) ($customer->pargar_account_id ?? 0),
'ItemId' => $itemId,
'ItemName' => $itemName,
'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' => $unitPrice,
'Count' => $count,
'Weight' => $weight,
'Price' => $totalPrice,
'Carat' => 750,
'Description' => self::accountingShopTradeDesc($customerDirection, $fromCart),
];
}
/**
* @return array<string, mixed>|null
*/
private function walletExportPayload(PargarSyncLog $log): ?array
{
$sync = $this->sync();
$payload = json_decode((string) $log->data, true) ?: [];
$kind = (string) ($payload['kind'] ?? ($log->type === PargarSyncService::TYPE_WALLET_GOLD ? 'gold' : 'cash'));
$signed = (float) ($payload['signed_amount'] ?? $log->amount ?? 0);
if (abs($signed) < ($kind === 'cash' ? 1 : 0.01)) {
$signed = (float) ($log->amount ?? 0);
// اگر علامت نبود، از desc حدس بزن — پیش‌فرض واریز مثبت
if (! isset($payload['signed_amount']) && is_string($log->desc) && str_contains($log->desc, 'برداشت')) {
$signed = -abs($signed);
} elseif (! isset($payload['signed_amount'])) {
$signed = abs($signed);
}
}
$customer = Customer::find((int) ($log->customer_id ?? 0));
$withdrawId = (int) ($log->withdraw_id ?? 0);
$orderId = $withdrawId > 0 ? 'W-' . $withdrawId : 'WLOG-' . $log->id;
$isDeposit = $signed >= 0;
2026-07-26 14:52:22 +03:30
// قرارداد پرگار (همان چیزی که سند سفارش هم با آن ساخته می‌شود):
// OrderType = 1 → سند «خرید» فروشگاه: وزن بدهکار، ریال بستانکار
// OrderType = -1 → سند «فروش» فروشگاه: وزن بستانکار، ریال بدهکار
// مانده در پرگار = بستانکار − بدهکار، پس برای اینکه شارژ در حساب مشتری مثبت بنشیند:
// شارژ طلای کیف اصلی → باید وزن بستانکار شود → OrderType = -1
// واریز ریالی → باید ریال بستانکار شود → OrderType = 1
$orderType = $kind === 'gold'
? ($isDeposit ? -1 : 1)
: ($isDeposit ? 1 : -1);
2026-07-20 15:52:42 +03:30
if ($kind === 'gold') {
return [
'OrderId' => $orderId,
'OrderType' => $orderType,
'PriceType' => 1,
'CustomerAccountId' => (int) ($customer->pargar_account_id ?? 0),
'ItemId' => $sync->pargarItemIdGold(),
'ItemName' => $sync->mainWalletGoldItemName(),
'OrderDate' => Jalalian::fromDateTime($log->date ?? $log->created_at)->format('Y/m/d-H:i:s'),
'Fee' => 0,
2026-07-20 19:11:04 +03:30
'Count' => 0,
2026-07-20 15:52:42 +03:30
'Weight' => abs($signed),
'Price' => 0,
'Carat' => 750,
'Description' => $isDeposit ? 'شارژ طلای کیف اصلی' : 'برداشت طلای کیف اصلی',
];
}
$rialItemId = $sync->pargarItemIdRial();
return [
'OrderId' => $orderId,
'OrderType' => $orderType,
'PriceType' => 1,
'CustomerAccountId' => (int) ($customer->pargar_account_id ?? 0),
'ItemId' => $rialItemId > 0 ? $rialItemId : $sync->pargarItemIdGold(),
'ItemName' => $isDeposit ? 'واریز ریالی' : 'برداشت ریالی',
'OrderDate' => Jalalian::fromDateTime($log->date ?? $log->created_at)->format('Y/m/d-H:i:s'),
'Fee' => 0,
2026-07-20 19:11:04 +03:30
'Count' => 0,
2026-07-20 15:52:42 +03:30
'Weight' => 0,
'Price' => abs($signed),
'Carat' => 750,
'Description' => $isDeposit ? 'واریز ریالی' : 'برداشت ریالی',
];
}
2026-07-05 16:43:34 +03:30
}