feat: shayegan inbound charges workflow and copper kilogram unit enforcement
This commit is contained in:
@@ -16,6 +16,7 @@ use App\Services\BalanceReportService;
|
||||
use App\Services\ConfigService;
|
||||
use App\Services\CustomerPresenceService;
|
||||
use App\Services\ReferralGiftService;
|
||||
use App\Services\ShayeganSyncService;
|
||||
use App\Services\WalletBalanceService;
|
||||
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||
|
||||
@@ -198,6 +199,23 @@ class CustomerController extends SuperController
|
||||
|
||||
$updated = $data === [] ? false : $customer->update($data);
|
||||
|
||||
// همگامسازی با شایگان در صورت تغییر دستی کد حسابداری
|
||||
if (array_key_exists('moshtari_code', $data) && app(ConfigService::class)->isShayeganAccounting()) {
|
||||
$newCode = $data['moshtari_code'];
|
||||
if ($newCode !== null && $newCode !== '') {
|
||||
try {
|
||||
$shayeganSync = app(ShayeganSyncService::class);
|
||||
$shayeganSync->registerCustomer($customer, $newCode);
|
||||
} catch (\Throwable $e) {
|
||||
\Illuminate\Support\Facades\Log::warning('shayegan.manual_code_sync_failed', [
|
||||
'customer_id' => $customer->id,
|
||||
'code' => $newCode,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'g' => $goldUpdated,
|
||||
'u' => $updated,
|
||||
|
||||
@@ -4,7 +4,10 @@ namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Shayegan;
|
||||
use App\Models\ShayeganInboundCharge;
|
||||
use App\Services\ConfigService;
|
||||
use App\Services\ShayeganClient;
|
||||
use App\Services\ShayeganInboundChargeService;
|
||||
use App\Services\ShayeganSyncService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
@@ -88,7 +91,7 @@ class ShayeganController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
$query = Shayegan::query()->orderByDesc('id');
|
||||
$query = Shayegan::with('customer')->orderByDesc('id');
|
||||
\App\DB\Te\TableEngine::create($query, $request)
|
||||
->initSearch(['desc', 'type', 'shayegan_number', 'sync_status'])
|
||||
->select(['*'])
|
||||
@@ -99,7 +102,7 @@ class ShayeganController extends Controller
|
||||
|
||||
public function show($id)
|
||||
{
|
||||
$row = Shayegan::findOrFail($id);
|
||||
$row = Shayegan::with('customer')->findOrFail($id);
|
||||
|
||||
return response()->json($row);
|
||||
}
|
||||
@@ -163,6 +166,132 @@ class ShayeganController extends Controller
|
||||
return response()->json(array_merge(['ok' => false, 'message' => $row->sync_log, 'row' => $row], $exchange), 422);
|
||||
}
|
||||
|
||||
/**
|
||||
* وبهوک دریافت شارژ حساب مشتری از پنل حسابداری شایگان
|
||||
*/
|
||||
public function inboundWebhook(Request $request, ShayeganInboundChargeService $inboundService)
|
||||
{
|
||||
$secret = app(ConfigService::class)->getString('shayegan_webhook_secret', '');
|
||||
$key = $request->header('X-Shayegan-Key') ?: $request->input('secret');
|
||||
|
||||
if ($secret !== '' && $key !== $secret) {
|
||||
return response()->json([
|
||||
'ok' => false,
|
||||
'message' => 'کلید امنیتی وبهوک شایگان نامعتبر است (X-Shayegan-Key).',
|
||||
], 403);
|
||||
}
|
||||
|
||||
$res = $inboundService->registerCharge($request->all(), 'webhook');
|
||||
|
||||
return response()->json($res, ($res['ok'] ?? false) ? 200 : 422);
|
||||
}
|
||||
|
||||
/**
|
||||
* دریافت لیست شارژهای در انتظار تایید برای نمایش اعلان در پنل ادمین
|
||||
*/
|
||||
public function pendingCharges()
|
||||
{
|
||||
if (! Schema::hasTable('shayegan_inbound_charges')) {
|
||||
return response()->json(['ok' => true, 'charges' => []]);
|
||||
}
|
||||
|
||||
$charges = ShayeganInboundCharge::with('customer')
|
||||
->where('status', 'pending')
|
||||
->orderByDesc('id')
|
||||
->limit(20)
|
||||
->get();
|
||||
|
||||
return response()->json([
|
||||
'ok' => true,
|
||||
'charges' => $charges,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* جدول شارژهای دریافتی از شایگان
|
||||
*/
|
||||
public function chargesTable(Request $request)
|
||||
{
|
||||
if (! Schema::hasTable('shayegan_inbound_charges')) {
|
||||
return response()->json([
|
||||
'rows' => [],
|
||||
'query' => [
|
||||
'limit' => (int) $request->input('limit', 20),
|
||||
'page' => 1,
|
||||
'total' => 0,
|
||||
'filters' => $request->input('filters', []),
|
||||
'search' => $request->input('search'),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
$query = ShayeganInboundCharge::with(['customer', 'approver'])->orderByDesc('id');
|
||||
|
||||
if ($request->filled('status')) {
|
||||
$query->where('status', $request->input('status'));
|
||||
}
|
||||
|
||||
if ($request->filled('search')) {
|
||||
$s = trim((string) $request->input('search'));
|
||||
$query->where(function ($q) use ($s) {
|
||||
$q->where('shayegan_number', 'like', "%{$s}%")
|
||||
->orWhere('customer_tafsil', 'like', "%{$s}%")
|
||||
->orWhereHas('customer', function ($cq) use ($s) {
|
||||
$cq->where('name', 'like', "%{$s}%")
|
||||
->orWhere('mobile', 'like', "%{$s}%")
|
||||
->orWhere('n_code', 'like', "%{$s}%");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$limit = max(1, (int) $request->input('limit', 20));
|
||||
$page = max(1, (int) $request->input('page', 1));
|
||||
$total = $query->count();
|
||||
$rows = $query->skip(($page - 1) * $limit)->take($limit)->get();
|
||||
|
||||
return response()->json([
|
||||
'rows' => $rows,
|
||||
'query' => [
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
'total' => $total,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* تایید شارژ و افزایش کیف پول مشتری در بورس مس
|
||||
*/
|
||||
public function approveCharge(Request $request, $id, ShayeganInboundChargeService $inboundService)
|
||||
{
|
||||
$charge = ShayeganInboundCharge::with('customer')->findOrFail($id);
|
||||
$res = $inboundService->approveCharge($charge, auth()->user());
|
||||
|
||||
return response()->json($res, ($res['ok'] ?? false) ? 200 : 422);
|
||||
}
|
||||
|
||||
/**
|
||||
* رد درخواست شارژ
|
||||
*/
|
||||
public function rejectCharge(Request $request, $id, ShayeganInboundChargeService $inboundService)
|
||||
{
|
||||
$charge = ShayeganInboundCharge::findOrFail($id);
|
||||
$reason = $request->input('reason');
|
||||
$res = $inboundService->rejectCharge($charge, auth()->user(), $reason);
|
||||
|
||||
return response()->json($res, ($res['ok'] ?? false) ? 200 : 422);
|
||||
}
|
||||
|
||||
/**
|
||||
* استعلام اسناد جدید از شایگان
|
||||
*/
|
||||
public function syncChargesFromShayegan(ShayeganInboundChargeService $inboundService)
|
||||
{
|
||||
$res = $inboundService->pollFromShayegan();
|
||||
|
||||
return response()->json($res, ($res['ok'] ?? false) ? 200 : 422);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $body
|
||||
* @return mixed
|
||||
|
||||
@@ -500,7 +500,7 @@ class Controller extends BaseController
|
||||
return self::isMainWalletProduct($productId) ? null : $productId;
|
||||
}
|
||||
|
||||
/** واحد وزن معاملات فلز — از ستینگ unit؛ پیشفرض گرم */
|
||||
/** واحد وزن معاملات فلز — در بورس مس پیشفرض کیلوگرم است */
|
||||
public static function tradeWeightUnit(): string
|
||||
{
|
||||
return self::resolveTradeWeightUnit(
|
||||
@@ -512,11 +512,11 @@ class Controller extends BaseController
|
||||
{
|
||||
$unit = trim((string) $value);
|
||||
|
||||
if ($unit === 'کیلوگرم' || $unit === 'kilogram' || $unit === 'kg') {
|
||||
return 'کیلوگرم';
|
||||
if ($unit === 'گرم' || $unit === 'gram' || $unit === 'g') {
|
||||
return 'گرم';
|
||||
}
|
||||
|
||||
return 'گرم';
|
||||
return 'کیلوگرم';
|
||||
}
|
||||
|
||||
public static function weightToGrams(float $value, ?string $fromUnit = null): float
|
||||
|
||||
Reference in New Issue
Block a user