fix pargar bug
This commit is contained in:
@@ -25,6 +25,7 @@ use App\Models\TransactionsAdmin;
|
||||
use App\Services\AssetSummaryService;
|
||||
use App\Services\BalanceReportService;
|
||||
use App\Services\ConfigService;
|
||||
use App\Services\PargarSyncService;
|
||||
use App\Services\WalletBalanceService;
|
||||
use App\Services\WalletBroadcastService;
|
||||
use Hekmatinasser\Verta\Verta;
|
||||
@@ -83,6 +84,20 @@ class WalletController extends Controller
|
||||
'active' => true
|
||||
], 3, false, true, $gold_block);
|
||||
|
||||
try {
|
||||
app(PargarSyncService::class)->queueWalletDocument(
|
||||
$customer,
|
||||
'cash',
|
||||
(float) $data['value'],
|
||||
[
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'source' => 'admin_charge2',
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
$message = 'کیف پول شما به مبلغ ' . self::formatSmsRialAmount($data['value']) . " ریال در تاریخ " . verta()->format('Y/n/j H:i:s') . " شارژ شد " . "\n"
|
||||
. $this->Config('name_fa');
|
||||
$this->Send($customer->mobile, $message);
|
||||
@@ -140,6 +155,21 @@ class WalletController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
app(PargarSyncService::class)->queueWalletDocument(
|
||||
$customer,
|
||||
'cash',
|
||||
(float) $data['value'],
|
||||
[
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'note' => $data['note'] ?? null,
|
||||
'source' => 'admin_cash',
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
//send sms to users and customer
|
||||
$status = $data['value'] > 0 ?" شارژ شد ": " کسر شد ";
|
||||
if (self::isSmsNotifEnabled('charge_notif')) {
|
||||
@@ -212,6 +242,23 @@ class WalletController extends Controller
|
||||
report($e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
app(PargarSyncService::class)->queueWalletDocument(
|
||||
$customer,
|
||||
'gold',
|
||||
(float) $data['value'],
|
||||
[
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'note' => $data['note'] ?? null,
|
||||
'product_id' => $representative?->id,
|
||||
'source' => 'admin_gold',
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
//send sms to users and customer
|
||||
$status = $data['value'] > 0 ?" شارژ شد ": " کسر شد ";
|
||||
$weightUnit = self::tradeWeightUnit();
|
||||
@@ -361,6 +408,23 @@ class WalletController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// فقط محصول متصل به کیف اصلی → سند طلای پرگار
|
||||
app(PargarSyncService::class)->queueWalletDocument(
|
||||
$customer,
|
||||
'gold',
|
||||
(float) $data['value'],
|
||||
[
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'note' => $data['note'] ?? null,
|
||||
'product_id' => $productId,
|
||||
'source' => 'admin_product',
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
$status = $deposit ? ' شارژ شد ' : ' کسر شد ';
|
||||
$formatted = self::formatSmsGoldWeight($data['value']);
|
||||
|
||||
|
||||
@@ -386,7 +386,10 @@ class CartController extends Controller
|
||||
|
||||
if ($config->isPargarAccounting()) {
|
||||
try {
|
||||
app(PargarSyncService::class)->recordTrade($order, true);
|
||||
app(PargarSyncService::class)->recordTrade($order, true, [
|
||||
'payment_kind' => PargarSyncService::PAYMENT_CASH,
|
||||
'product_id' => null,
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
@@ -8,13 +8,11 @@ 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;
|
||||
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||
|
||||
@@ -164,44 +162,41 @@ class PargarInboundController extends Controller
|
||||
|
||||
public function listOrders(Request $request)
|
||||
{
|
||||
$documents = collect();
|
||||
|
||||
$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));
|
||||
foreach ($orders as $order) {
|
||||
$payload = $this->orderExportPayload($order);
|
||||
if ($payload === null) {
|
||||
continue;
|
||||
}
|
||||
$documents->push($payload);
|
||||
}
|
||||
|
||||
// direction اپ: 1=خرید مشتری، 2=فروش مشتری
|
||||
// OrderType پرگار از دید فروشگاه است: خرید مشتری = فروش فروشگاه (-1)، فروش مشتری = خرید فروشگاه (1)
|
||||
$isCustomerBuy = (int) ($order->direction ?? 1) === 1;
|
||||
$customerDirection = (int) ($order->direction ?? 0);
|
||||
$walletLogs = PargarSyncLog::query()
|
||||
->whereIn('type', [PargarSyncService::TYPE_WALLET_CASH, PargarSyncService::TYPE_WALLET_GOLD])
|
||||
->where('sync_status', PargarSyncService::STATUS_PENDING)
|
||||
->orderBy('id')
|
||||
->limit(100)
|
||||
->get();
|
||||
|
||||
return [
|
||||
'OrderId' => (string) $order->id,
|
||||
'OrderType' => $isCustomerBuy ? -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' => self::accountingShopTradeDesc($customerDirection, $this->isCartOrder($order)),
|
||||
];
|
||||
})->values();
|
||||
foreach ($walletLogs as $log) {
|
||||
$payload = $this->walletExportPayload($log);
|
||||
if ($payload !== null) {
|
||||
$documents->push($payload);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'state' => 'true',
|
||||
'msg' => '',
|
||||
'data' => [
|
||||
'documents' => $documents,
|
||||
'documents' => $documents->values(),
|
||||
'duplicated' => 'false',
|
||||
'result' => 'OK',
|
||||
],
|
||||
@@ -242,7 +237,7 @@ class PargarInboundController extends Controller
|
||||
PargarSyncLog::create([
|
||||
'customer_id' => $customer?->id,
|
||||
'desc' => 'دریافت اسناد از پرگار',
|
||||
'type' => 'document',
|
||||
'type' => PargarSyncService::TYPE_DOCUMENT,
|
||||
'sync_status' => PargarSyncService::STATUS_SUCCESS,
|
||||
'pargar_ref' => $accountId,
|
||||
'data' => json_encode($data, JSON_UNESCAPED_UNICODE),
|
||||
@@ -272,33 +267,35 @@ class PargarInboundController extends Controller
|
||||
$goldInv = isset($data['GoldInv']) ? (float) str_replace('/', '.', (string) $data['GoldInv']) : 0;
|
||||
$rialInv = isset($data['RialInv']) ? (float) str_replace('/', '.', (string) $data['RialInv']) : 0;
|
||||
|
||||
// خواندن و نوشتن روی همان کیف اصلی مشتری — نه first() تصادفی
|
||||
// فقط مقایسه برای لاگ — اپ source of truth است؛ کیف را از مانده پرگار عوض نکن
|
||||
$ownerType = (int) ($customer->type ?? 2);
|
||||
$walletInterface = new WalletInterface($customer->id, $ownerType);
|
||||
$wallet = $walletInterface->wallet;
|
||||
|
||||
$goldDiff = $goldInv - (float) ($wallet->gold ?? 0);
|
||||
$rialDiff = $rialInv - (float) ($wallet->cash ?? 0);
|
||||
$appGold = (float) ($wallet->gold ?? 0);
|
||||
$appCash = (float) ($wallet->cash ?? 0);
|
||||
$goldDiff = $goldInv - $appGold;
|
||||
$rialDiff = $rialInv - $appCash;
|
||||
$hasDiff = abs($goldDiff) >= 0.01 || abs($rialDiff) >= 1;
|
||||
|
||||
if (abs($goldDiff) >= 0.01 || abs($rialDiff) >= 1) {
|
||||
new TransactionInterface($walletInterface, [
|
||||
'cash' => $rialDiff,
|
||||
'gold' => $goldDiff,
|
||||
'title' => 'تعدیل حسابداری پرگار',
|
||||
'expire_at' => now(),
|
||||
'active' => true,
|
||||
'start_at' => now(),
|
||||
], 22, $goldDiff > 0, $rialDiff > 0);
|
||||
}
|
||||
$desc = $hasDiff
|
||||
? 'اختلاف مانده پرگار با اپ — کیف اپ دست نخورده'
|
||||
: 'دریافت مانده از پرگار — بدون اختلاف';
|
||||
|
||||
PargarSyncLog::create([
|
||||
'customer_id' => $customer->id,
|
||||
'desc' => 'دریافت مانده از پرگار',
|
||||
'type' => 'mande',
|
||||
'desc' => $desc,
|
||||
'type' => PargarSyncService::TYPE_MANDE,
|
||||
'amount' => $goldInv,
|
||||
'sync_status' => PargarSyncService::STATUS_SUCCESS,
|
||||
'pargar_ref' => $accountId,
|
||||
'data' => json_encode($data, JSON_UNESCAPED_UNICODE),
|
||||
'data' => json_encode(array_merge($data, [
|
||||
'app_gold' => $appGold,
|
||||
'app_cash' => $appCash,
|
||||
'gold_diff' => $goldDiff,
|
||||
'rial_diff' => $rialDiff,
|
||||
'wallet_adjusted' => false,
|
||||
]), JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
@@ -495,4 +492,162 @@ class PargarInboundController extends Controller
|
||||
->whereIn('desc', ['سبد خرید', 'فروش سبد به مشتری'])
|
||||
->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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);
|
||||
$amount = (float) ($order->amount ?? 0);
|
||||
$totalPrice = (float) ($order->total_price ?? $order->payment_amount ?? 0);
|
||||
$unitPrice = (float) ($order->price ?? 0);
|
||||
|
||||
$isCountBased = $product
|
||||
? self::isCountBasedProduct(self::productUnitPayload($product))
|
||||
: false;
|
||||
|
||||
$count = 1;
|
||||
$weight = $amount;
|
||||
if ($isCountBased && $number > 0) {
|
||||
$count = max(1, (int) round($number));
|
||||
$weight = $amount;
|
||||
} elseif ($number > 0 && abs($number - $amount) > 0.0001) {
|
||||
$count = max(1, (int) round($number));
|
||||
}
|
||||
|
||||
$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);
|
||||
$tradesMainGold = $tradedProductId <= 0
|
||||
|| app(ConfigService::class)->isMainWalletProduct($tradedProductId);
|
||||
|
||||
// اثر مانده از روش پرداخت؛ وزن طلا فقط وقتی کالای معامله یا پرداخت به کیف اصلی مربوط است
|
||||
if ($paymentKind === PargarSyncService::PAYMENT_CASH) {
|
||||
if ($tradesMainGold) {
|
||||
// خرید/فروش آبشده کیفاصلی با نقدی: وزن + مبلغ
|
||||
$itemId = $sync->pargarItemIdGold();
|
||||
} else {
|
||||
// محصول غیر اصلی با پرداخت نقدی: فقط ریال
|
||||
$rialItemId = $sync->pargarItemIdRial();
|
||||
$itemId = $rialItemId > 0 ? $rialItemId : $sync->pargarItemIdGold();
|
||||
$weight = 0;
|
||||
$count = 1;
|
||||
}
|
||||
} elseif ($paymentKind === PargarSyncService::PAYMENT_MAIN_GOLD) {
|
||||
$itemId = $sync->pargarItemIdGold();
|
||||
$itemName = $sync->mainWalletGoldItemName();
|
||||
$paymentGold = (float) ($payload['payment_gold'] ?? $amount);
|
||||
$weight = abs($paymentGold);
|
||||
$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;
|
||||
// OrderType از دید فروشگاه: واریز به مشتری = فروشگاه بدهکار؟ قرارداد قبلی خرید مشتری = -1
|
||||
// واریز ریالی مشتری ≈ افزایش بدهی فروشگاه به مشتری از نظر حساب → مشابه خرید نیست؛
|
||||
// برای واریز: OrderType=1 (ورود وجه به حساب مشتری در پرگار بسته به نرمافزار)
|
||||
// همراستا با آذین: اسناد کیف را با OrderType بر اساس علامت میفرستیم
|
||||
$orderType = $isDeposit ? 1 : -1;
|
||||
|
||||
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,
|
||||
'Count' => 1,
|
||||
'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,
|
||||
'Count' => 1,
|
||||
'Weight' => 0,
|
||||
'Price' => abs($signed),
|
||||
'Carat' => 750,
|
||||
'Description' => $isDeposit ? 'واریز ریالی' : 'برداشت ریالی',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +208,30 @@ class SingleOrderController extends Controller
|
||||
|
||||
if ($config->isPargarAccounting()) {
|
||||
try {
|
||||
app(\App\Services\PargarSyncService::class)->recordTrade($data['order'] ?? null);
|
||||
$paymentProductId = (int) ($data['payment_product_id'] ?? 0);
|
||||
$paymentKind = app(\App\Services\PargarSyncService::class)
|
||||
->inferPaymentKindFromContext([
|
||||
'payment_product_id' => $paymentProductId,
|
||||
]);
|
||||
// خرید/فروش عادی از کیف ریالی (بدون payment_product_id) = نقدی
|
||||
if ($paymentProductId <= 0) {
|
||||
$paymentKind = \App\Services\PargarSyncService::PAYMENT_CASH;
|
||||
}
|
||||
$paymentGold = null;
|
||||
if ($paymentKind === \App\Services\PargarSyncService::PAYMENT_MAIN_GOLD) {
|
||||
$paymentGold = (float) ($data['total_amount'] ?? $data['amount'] ?? 0);
|
||||
}
|
||||
app(\App\Services\PargarSyncService::class)->recordTrade(
|
||||
$data['order'] ?? null,
|
||||
false,
|
||||
[
|
||||
'payment_kind' => $paymentKind,
|
||||
'payment_product_id' => $paymentProductId > 0 ? $paymentProductId : null,
|
||||
'product_id' => (int) ($data['product_id'] ?? 0) ?: null,
|
||||
'number' => isset($data['number']) ? (float) $data['number'] : null,
|
||||
'payment_gold' => $paymentGold,
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
@@ -182,6 +182,21 @@ class paypingController extends Controller
|
||||
'active' => true,
|
||||
], 3, false, true);
|
||||
|
||||
try {
|
||||
app(\App\Services\PargarSyncService::class)->queueWalletDocument(
|
||||
$User,
|
||||
'cash',
|
||||
(float) ($GTransaction['amount'] * 10),
|
||||
[
|
||||
'withdraw_id' => $Withdraw->id,
|
||||
'note' => 'واریز درگاه',
|
||||
'source' => 'gateway',
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
$message = 'کاربر ' . $Withdraw->customer->name . ' با شماره موبایل ' . $Withdraw->customer->mobile
|
||||
. ' حساب خود را به مقدار ' . number_format($Withdraw->cash) . ' ریال شارژ کرد. با تشکر، ' . $this->Config('name_fa');
|
||||
|
||||
@@ -238,6 +253,21 @@ class paypingController extends Controller
|
||||
'active' => true,
|
||||
], 3, false, true);
|
||||
|
||||
try {
|
||||
app(\App\Services\PargarSyncService::class)->queueWalletDocument(
|
||||
$User,
|
||||
'cash',
|
||||
(float) ($decodedResponse['data']['amount'] * 10),
|
||||
[
|
||||
'withdraw_id' => (int) $Withdraw->id,
|
||||
'note' => 'واریز درگاه',
|
||||
'source' => 'gateway',
|
||||
]
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
if ($this->cfg()->getBool('payping_fin_sync_enabled', (bool) config('payment.payping_fin_sync_enabled', false))) {
|
||||
$finUrl = $this->cfg()->getString('payping_fin_url', 'https://limangold.ir/kernel/admin/fin');
|
||||
$finToken = $this->cfg()->getString('payping_fin_token', '');
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Services;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Order;
|
||||
use App\Models\PargarSyncLog;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
@@ -14,6 +15,17 @@ class PargarSyncService
|
||||
public const STATUS_SUCCESS = 'success';
|
||||
public const STATUS_FAILED = 'failed';
|
||||
|
||||
public const TYPE_CUSTOMER = 'customer';
|
||||
public const TYPE_ORDER = 'order';
|
||||
public const TYPE_MANDE = 'mande';
|
||||
public const TYPE_DOCUMENT = 'document';
|
||||
public const TYPE_WALLET_CASH = 'wallet_cash';
|
||||
public const TYPE_WALLET_GOLD = 'wallet_gold';
|
||||
|
||||
public const PAYMENT_CASH = 'cash';
|
||||
public const PAYMENT_MAIN_GOLD = 'main_gold';
|
||||
public const PAYMENT_OTHER_PRODUCT = 'other_product';
|
||||
|
||||
public function buildLog(mixed $response = null, ?string $extra = null): string
|
||||
{
|
||||
$parts = array_filter([
|
||||
@@ -93,7 +105,7 @@ class PargarSyncService
|
||||
{
|
||||
$existing = PargarSyncLog::query()
|
||||
->where('customer_id', $customer->id)
|
||||
->where('type', 'customer')
|
||||
->where('type', self::TYPE_CUSTOMER)
|
||||
->where('sync_status', self::STATUS_PENDING)
|
||||
->latest('id')
|
||||
->first();
|
||||
@@ -105,7 +117,7 @@ class PargarSyncService
|
||||
return PargarSyncLog::create([
|
||||
'customer_id' => $customer->id,
|
||||
'desc' => 'در انتظار دریافت توسط پرگار',
|
||||
'type' => 'customer',
|
||||
'type' => self::TYPE_CUSTOMER,
|
||||
'sync_status' => self::STATUS_PENDING,
|
||||
'data' => json_encode(['handler' => 'exportCustomer'], JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
@@ -132,7 +144,84 @@ class PargarSyncService
|
||||
];
|
||||
}
|
||||
|
||||
public function recordTrade(?Order $order, bool $fromCart = false): ?PargarSyncLog
|
||||
/**
|
||||
* صف سند کیف برای سینک مانده پرگار با اپ.
|
||||
*
|
||||
* @param 'cash'|'gold' $kind
|
||||
* @param array{withdraw_id?:int|null,note?:string|null,product_id?:int|null,source?:string|null} $meta
|
||||
*/
|
||||
public function queueWalletDocument(
|
||||
Customer $customer,
|
||||
string $kind,
|
||||
float $signedAmount,
|
||||
array $meta = []
|
||||
): ?PargarSyncLog {
|
||||
if (! $this->isSyncEnabled() || ! $this->hasSyncTable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (abs($signedAmount) < ($kind === 'cash' ? 1 : 0.01)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($kind === 'gold') {
|
||||
$productId = (int) ($meta['product_id'] ?? 0);
|
||||
if ($productId > 0 && ! app(ConfigService::class)->isMainWalletProduct($productId)) {
|
||||
return null;
|
||||
}
|
||||
} elseif ($kind !== 'cash') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$withdrawId = isset($meta['withdraw_id']) ? (int) $meta['withdraw_id'] : null;
|
||||
$type = $kind === 'cash' ? self::TYPE_WALLET_CASH : self::TYPE_WALLET_GOLD;
|
||||
|
||||
if ($withdrawId) {
|
||||
$existing = PargarSyncLog::query()
|
||||
->where('withdraw_id', $withdrawId)
|
||||
->where('type', $type)
|
||||
->latest('id')
|
||||
->first();
|
||||
if ($existing) {
|
||||
return $existing;
|
||||
}
|
||||
}
|
||||
|
||||
$isDeposit = $signedAmount > 0;
|
||||
if ($kind === 'cash') {
|
||||
$desc = $isDeposit ? 'واریز ریالی — ارسال به پرگار' : 'برداشت ریالی — ارسال به پرگار';
|
||||
} else {
|
||||
$desc = $isDeposit ? 'شارژ طلای کیف اصلی — ارسال به پرگار' : 'برداشت طلای کیف اصلی — ارسال به پرگار';
|
||||
}
|
||||
|
||||
return PargarSyncLog::create([
|
||||
'customer_id' => $customer->id,
|
||||
'amount' => abs($signedAmount),
|
||||
'desc' => $desc,
|
||||
'withdraw_id' => $withdrawId,
|
||||
'date' => now(),
|
||||
'type' => $type,
|
||||
'sync_status' => self::STATUS_PENDING,
|
||||
'data' => json_encode([
|
||||
'handler' => 'exportWallet',
|
||||
'kind' => $kind,
|
||||
'signed_amount' => $signedAmount,
|
||||
'note' => $meta['note'] ?? null,
|
||||
'product_id' => $meta['product_id'] ?? null,
|
||||
'source' => $meta['source'] ?? null,
|
||||
], JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{
|
||||
* payment_kind?: string,
|
||||
* payment_product_id?: int|null,
|
||||
* product_id?: int|null,
|
||||
* number?: float|null
|
||||
* } $context
|
||||
*/
|
||||
public function recordTrade(?Order $order, bool $fromCart = false, array $context = []): ?PargarSyncLog
|
||||
{
|
||||
if (! $order || ! $order->id || ! $this->isSyncEnabled()) {
|
||||
return null;
|
||||
@@ -146,29 +235,123 @@ class PargarSyncService
|
||||
$direction = (int) ($order->direction ?? 0);
|
||||
$desc = \App\Http\Controllers\Controller::accountingShopTradeDesc($direction, $fromCart);
|
||||
|
||||
$paymentKind = $context['payment_kind']
|
||||
?? $this->inferPaymentKindFromContext($context);
|
||||
|
||||
$payload = [
|
||||
'handler' => 'exportOrder',
|
||||
'direction' => $direction,
|
||||
'price' => $order->price,
|
||||
'total_price' => $order->total_price,
|
||||
'payment_kind' => $paymentKind,
|
||||
'payment_product_id' => $context['payment_product_id'] ?? null,
|
||||
'product_id' => $context['product_id'] ?? $order->product_id ?? null,
|
||||
'number' => $context['number'] ?? null,
|
||||
'payment_gold' => $context['payment_gold'] ?? null,
|
||||
'from_cart' => $fromCart,
|
||||
];
|
||||
|
||||
// تهاتر بین دو محصول غیر اصلی — روی ریال/طلای پرگار اثر ندارد
|
||||
if ($paymentKind === self::PAYMENT_OTHER_PRODUCT) {
|
||||
$order->pargar_confirmed_at = now();
|
||||
$order->save();
|
||||
|
||||
return PargarSyncLog::create([
|
||||
'customer_id' => $order->customer_id,
|
||||
'amount' => $order->amount,
|
||||
'desc' => $desc . ' (تهاتر محصول — بدون سند ریال/طلای پرگار)',
|
||||
'order_id' => $order->id,
|
||||
'date' => $order->pay_at ?? $order->created_at,
|
||||
'type' => self::TYPE_ORDER,
|
||||
'sync_status' => self::STATUS_SUCCESS,
|
||||
'pargar_ref' => 'skip:barter',
|
||||
'data' => json_encode($payload, JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
}
|
||||
|
||||
return PargarSyncLog::create([
|
||||
'customer_id' => $order->customer_id,
|
||||
'amount' => $order->amount,
|
||||
'desc' => $desc,
|
||||
'order_id' => $order->id,
|
||||
'date' => $order->pay_at ?? $order->created_at,
|
||||
'type' => 'order',
|
||||
'type' => self::TYPE_ORDER,
|
||||
'sync_status' => self::STATUS_PENDING,
|
||||
'data' => json_encode([
|
||||
'handler' => 'exportOrder',
|
||||
'direction' => $direction,
|
||||
'price' => $order->price,
|
||||
'total_price' => $order->total_price,
|
||||
], JSON_UNESCAPED_UNICODE),
|
||||
'data' => json_encode($payload, JSON_UNESCAPED_UNICODE),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{payment_kind?: string, payment_product_id?: int|null} $context
|
||||
*/
|
||||
public function inferPaymentKindFromContext(array $context): string
|
||||
{
|
||||
if (! empty($context['payment_kind'])) {
|
||||
return (string) $context['payment_kind'];
|
||||
}
|
||||
|
||||
$paymentProductId = (int) ($context['payment_product_id'] ?? 0);
|
||||
if ($paymentProductId <= 0) {
|
||||
return self::PAYMENT_CASH;
|
||||
}
|
||||
|
||||
return app(ConfigService::class)->isMainWalletProduct($paymentProductId)
|
||||
? self::PAYMENT_MAIN_GOLD
|
||||
: self::PAYMENT_OTHER_PRODUCT;
|
||||
}
|
||||
|
||||
public function confirmOrders(array $orderIds): array
|
||||
{
|
||||
$confirmed = 0;
|
||||
|
||||
foreach ($orderIds as $orderId) {
|
||||
$order = Order::find($orderId);
|
||||
$id = trim((string) $orderId);
|
||||
if ($id === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_starts_with(strtoupper($id), 'W-')) {
|
||||
$withdrawId = (int) substr($id, 2);
|
||||
if ($withdrawId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$log = PargarSyncLog::query()
|
||||
->where('withdraw_id', $withdrawId)
|
||||
->whereIn('type', [self::TYPE_WALLET_CASH, self::TYPE_WALLET_GOLD])
|
||||
->where('sync_status', self::STATUS_PENDING)
|
||||
->latest('id')
|
||||
->first();
|
||||
|
||||
if ($log) {
|
||||
$this->markSuccess($log, $id, ['OrderId' => $id]);
|
||||
$confirmed++;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_starts_with(strtoupper($id), 'WLOG-')) {
|
||||
$logId = (int) substr($id, 5);
|
||||
if ($logId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$log = PargarSyncLog::query()
|
||||
->where('id', $logId)
|
||||
->whereIn('type', [self::TYPE_WALLET_CASH, self::TYPE_WALLET_GOLD])
|
||||
->where('sync_status', self::STATUS_PENDING)
|
||||
->first();
|
||||
|
||||
if ($log) {
|
||||
$this->markSuccess($log, $id, ['OrderId' => $id]);
|
||||
$confirmed++;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$order = Order::find($id);
|
||||
if (! $order) {
|
||||
continue;
|
||||
}
|
||||
@@ -227,6 +410,21 @@ class PargarSyncService
|
||||
];
|
||||
}
|
||||
|
||||
if ($handler === 'exportWallet') {
|
||||
PargarSyncLog::where('id', $log->id)->update([
|
||||
'sync_status' => self::STATUS_PENDING,
|
||||
'sync_log' => null,
|
||||
'pargar_ref' => null,
|
||||
]);
|
||||
$log->refresh();
|
||||
|
||||
return [
|
||||
'ok' => true,
|
||||
'message' => 'سند کیف دوباره در صف ارسال به پرگار قرار گرفت',
|
||||
'pargar' => $log,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'ok' => false,
|
||||
'message' => $log->sync_log ?: 'ارسال مجدد به پرگار ناموفق بود',
|
||||
@@ -240,11 +438,15 @@ class PargarSyncService
|
||||
return 'exportOrder';
|
||||
}
|
||||
|
||||
if ($log->type === 'customer') {
|
||||
if ($log->type === self::TYPE_CUSTOMER) {
|
||||
return 'exportCustomer';
|
||||
}
|
||||
|
||||
if ($log->type === 'mande') {
|
||||
if (in_array($log->type, [self::TYPE_WALLET_CASH, self::TYPE_WALLET_GOLD], true)) {
|
||||
return 'exportWallet';
|
||||
}
|
||||
|
||||
if ($log->type === self::TYPE_MANDE) {
|
||||
return 'importMande';
|
||||
}
|
||||
|
||||
@@ -264,4 +466,37 @@ class PargarSyncService
|
||||
{
|
||||
return Schema::hasTable('pargar_sync_logs');
|
||||
}
|
||||
|
||||
public function pargarItemIdRial(): int
|
||||
{
|
||||
$raw = trim(app(ConfigService::class)->getString('pargar_item_id_rial', '0'));
|
||||
|
||||
return max(0, (int) $raw);
|
||||
}
|
||||
|
||||
public function pargarItemIdGold(): int
|
||||
{
|
||||
$raw = trim(app(ConfigService::class)->getString('pargar_item_id_gold', '11'));
|
||||
$id = (int) $raw;
|
||||
|
||||
return $id > 0 ? $id : 11;
|
||||
}
|
||||
|
||||
public function mainWalletGoldItemName(): string
|
||||
{
|
||||
$product = app(ConfigService::class)->mainWalletRepresentativeProduct();
|
||||
$title = trim((string) ($product?->title ?? ''));
|
||||
|
||||
return $title !== '' ? $title : 'آبشده';
|
||||
}
|
||||
|
||||
public function resolveOrderProduct(?Order $order, ?array $payload = null): ?Product
|
||||
{
|
||||
$productId = (int) ($payload['product_id'] ?? $order?->product_id ?? 0);
|
||||
if ($productId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Product::find($productId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,6 +490,16 @@ INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `de
|
||||
SELECT 'pargar_api_token', '', 'توکن ثابت API پرگار', 0, 1, NULL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'pargar_api_token' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||
SELECT 'pargar_item_id_rial', '0', 'کد کالای ریال پرگار', 0, 1,
|
||||
'کد کالا برای اسناد واریز/برداشت ریالی در پرگار. صفر = استفاده از کد طلا با وزن صفر.', 'number'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'pargar_item_id_rial' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`, `type`)
|
||||
SELECT 'pargar_item_id_gold', '11', 'کد کالای طلا پرگار', 0, 1,
|
||||
'کد کالای طلا (کیف اصلی / آبشده) در پرگار برای اسناد وزندار.', 'number'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'pargar_item_id_gold' LIMIT 1);
|
||||
|
||||
INSERT INTO `settings` (`key`, `value`, `title_fa`, `can_edit`, `is_active`, `description`)
|
||||
SELECT 'telegram_bot_token', '', 'توکن بات تلگرام', 0, 1, NULL
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `settings` WHERE `key` = 'telegram_bot_token' LIMIT 1);
|
||||
@@ -915,7 +925,8 @@ UPDATE `settings` SET `type` = 'number' WHERE `key` IN (
|
||||
'fee_service_charge_percentage', 'fee_free', 'service_charge_percentage',
|
||||
'montzar_product_id', 'gift_for_referrer', 'gift_for_referral',
|
||||
'payping_fin_customer_id', 'tahesab_port', 'referral_limit',
|
||||
'deposit_sms_support_number'
|
||||
'deposit_sms_support_number',
|
||||
'pargar_item_id_rial', 'pargar_item_id_gold'
|
||||
);
|
||||
|
||||
-- text (بقیه — URL، توکن، کلید API، ساعت، ...)
|
||||
@@ -928,6 +939,7 @@ UPDATE `settings` SET `type` = 'text' WHERE `key` IN (
|
||||
'payping_start_url', 'payping_verify_url', 'payping_gateway_items', 'payping_fin_url',
|
||||
'payping_fin_token', 'tahesab_host', 'tahesab_token', 'tahesab_db',
|
||||
'pargar_username', 'pargar_password', 'pargar_api_token',
|
||||
'pargar_item_id_rial', 'pargar_item_id_gold',
|
||||
'node_client_id', 'node_shared_secret',
|
||||
'sse_path',
|
||||
'tahesab_bank_account', 'telegram_bot_token', 'bale_bot_token', 'support_messenger_id',
|
||||
@@ -1624,7 +1636,8 @@ UPDATE `settings` SET `type` = 'number' WHERE `key` IN (
|
||||
'fee_service_charge_percentage', 'fee_free', 'service_charge_percentage',
|
||||
'montzar_product_id', 'gift_for_referrer', 'gift_for_referral',
|
||||
'payping_fin_customer_id', 'tahesab_port', 'referral_limit',
|
||||
'deposit_sms_support_number'
|
||||
'deposit_sms_support_number',
|
||||
'pargar_item_id_rial', 'pargar_item_id_gold'
|
||||
);
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
@@ -1643,7 +1656,8 @@ UPDATE `settings` SET `can_edit` = 0, `is_active` = 0 WHERE `key` IN ('send_to_t
|
||||
UPDATE `settings` SET `can_edit` = 0 WHERE `key` IN (
|
||||
'accounting_provider',
|
||||
'tahesab_host', 'tahesab_port', 'tahesab_token', 'tahesab_db', 'tahesab_bank_account',
|
||||
'pargar_username', 'pargar_password', 'pargar_api_token'
|
||||
'pargar_username', 'pargar_password', 'pargar_api_token',
|
||||
'pargar_item_id_rial', 'pargar_item_id_gold'
|
||||
);
|
||||
UPDATE `settings` SET `title_fa` = 'سیستم حسابداری', `type` = 'select', `description` = 'none,pargar,tahesab'
|
||||
WHERE `key` = 'accounting_provider';
|
||||
|
||||
Reference in New Issue
Block a user