feat: landing settings, instant withdraw deduct, and OTP site URL
Add has_landing plus landing_* deploy keys, deduct balance on withdraw request, keep app_url for SMS login links, and clarify Zarin rial wallet document titles. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -121,8 +121,11 @@ class ConfigService
|
||||
try {
|
||||
$row = Setting::where('key', $key)->first();
|
||||
|
||||
if ($row !== null && $row->is_active && $row->value !== null && $row->value !== '') {
|
||||
return $row->value;
|
||||
if ($row !== null && $row->value !== null && $row->value !== '') {
|
||||
// app_url لینک ورود پیامک است — حتی اگر سوییچ is_active خاموش باشد باید خوانده شود
|
||||
if ($key === 'app_url' || $row->is_active) {
|
||||
return $row->value;
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
// DB در دسترس نیست (deploy / .env اشتباه) — از config/price_providers.php استفاده شود
|
||||
@@ -1357,7 +1360,7 @@ class ConfigService
|
||||
return '';
|
||||
}
|
||||
|
||||
/** Full user-facing site URL, e.g. https://example.ir — prefers settings.app_url */
|
||||
/** Full user-facing site URL, e.g. https://example.ir — فقط settings.app_url؛ هاست API جایگزین نمیشود */
|
||||
public function resolvePublicSiteUrl(?\Illuminate\Http\Request $request = null): string
|
||||
{
|
||||
$fromAppUrl = $this->normalizedAppUrl();
|
||||
@@ -1366,23 +1369,21 @@ class ConfigService
|
||||
}
|
||||
|
||||
if ($request !== null) {
|
||||
$origin = rtrim(trim((string) $request->getSchemeAndHttpHost()), '/');
|
||||
$host = $this->parseHostFromUrl($origin);
|
||||
if ($this->isUsableHost($host)) {
|
||||
$origin = $this->originIfNotApiHost($request);
|
||||
if ($origin !== '') {
|
||||
return $origin;
|
||||
}
|
||||
}
|
||||
|
||||
if (! app()->runningInConsole() && request()) {
|
||||
$origin = rtrim(trim((string) request()->getSchemeAndHttpHost()), '/');
|
||||
$host = $this->parseHostFromUrl($origin);
|
||||
if ($this->isUsableHost($host)) {
|
||||
$origin = $this->originIfNotApiHost(request());
|
||||
if ($origin !== '') {
|
||||
return $origin;
|
||||
}
|
||||
}
|
||||
|
||||
$host = $this->resolvePublicHost($request);
|
||||
if ($host !== '') {
|
||||
if ($host !== '' && ! $this->hostMatchesLaravelAppUrl($host)) {
|
||||
return 'https://' . $host;
|
||||
}
|
||||
|
||||
@@ -1400,17 +1401,23 @@ class ConfigService
|
||||
{
|
||||
$candidates = [];
|
||||
|
||||
$appUrlHost = $this->parseHostFromUrl((string) $this->get('app_url', ''));
|
||||
$appUrlHost = $this->parseHostFromUrl($this->getString('app_url', ''));
|
||||
if ($appUrlHost !== '') {
|
||||
$candidates[] = $appUrlHost;
|
||||
}
|
||||
|
||||
if ($request !== null) {
|
||||
$candidates[] = trim((string) $request->getHost());
|
||||
$host = trim((string) $request->getHost());
|
||||
if (! $this->hostMatchesLaravelAppUrl($host)) {
|
||||
$candidates[] = $host;
|
||||
}
|
||||
}
|
||||
|
||||
if (! app()->runningInConsole() && request()) {
|
||||
$candidates[] = trim((string) request()->getHost());
|
||||
$host = trim((string) request()->getHost());
|
||||
if (! $this->hostMatchesLaravelAppUrl($host)) {
|
||||
$candidates[] = $host;
|
||||
}
|
||||
}
|
||||
|
||||
return $candidates;
|
||||
@@ -1419,7 +1426,7 @@ class ConfigService
|
||||
/** settings.app_url as https://host… without trailing slash; empty if unusable */
|
||||
private function normalizedAppUrl(): string
|
||||
{
|
||||
$raw = trim((string) $this->get('app_url', ''));
|
||||
$raw = $this->getString('app_url', '');
|
||||
if ($raw === '') {
|
||||
return '';
|
||||
}
|
||||
@@ -1443,6 +1450,28 @@ class ConfigService
|
||||
return $origin;
|
||||
}
|
||||
|
||||
/** هاست Laravel APP_URL همان بکاند است — نباید لینک ورود اپ شود */
|
||||
private function hostMatchesLaravelAppUrl(string $host): bool
|
||||
{
|
||||
$apiHost = $this->parseHostFromUrl((string) config('app.url', ''));
|
||||
if ($apiHost === '' || ! $this->isUsableHost($apiHost)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->normalizeHost($host) === $this->normalizeHost($apiHost);
|
||||
}
|
||||
|
||||
private function originIfNotApiHost(\Illuminate\Http\Request $request): string
|
||||
{
|
||||
$origin = rtrim(trim((string) $request->getSchemeAndHttpHost()), '/');
|
||||
$host = $this->parseHostFromUrl($origin);
|
||||
if (! $this->isUsableHost($host) || $this->hostMatchesLaravelAppUrl($host)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $origin;
|
||||
}
|
||||
|
||||
private function isUsableHost(string $host): bool
|
||||
{
|
||||
$host = strtolower(trim($host));
|
||||
|
||||
@@ -11,7 +11,7 @@ use App\Models\Setting;
|
||||
class SuperAdminProgramSettingsOverlay
|
||||
{
|
||||
/**
|
||||
* فقط این ۱۵ دسترسی از سوپرادمین خوانده میشود.
|
||||
* فقط این ۱۶ دسترسی از سوپرادمین خوانده میشود.
|
||||
* هر کلید دیگری (قیمت، ساعت کاری، برندینگ، …) مال پنل خانگی است.
|
||||
*/
|
||||
public const SUPERADMIN_OWNED_KEYS = [
|
||||
@@ -23,6 +23,7 @@ class SuperAdminProgramSettingsOverlay
|
||||
'enable_gold_credit',
|
||||
'enable_product_funds',
|
||||
'group_sms',
|
||||
'has_landing',
|
||||
'has_page_earn_money',
|
||||
'has_page_gift_card',
|
||||
'has_page_notification',
|
||||
@@ -40,6 +41,7 @@ class SuperAdminProgramSettingsOverlay
|
||||
'enable_conditional_order',
|
||||
'enable_gold_credit',
|
||||
'enable_product_funds',
|
||||
'has_landing',
|
||||
'has_page_earn_money',
|
||||
'has_page_gift_card',
|
||||
'has_page_notification',
|
||||
@@ -119,7 +121,7 @@ class SuperAdminProgramSettingsOverlay
|
||||
}
|
||||
|
||||
/**
|
||||
* آخرین مقادیر ۱۵ دسترسی را در settings لوکال ذخیره میکند (can_edit=0).
|
||||
* آخرین مقادیر ۱۶ دسترسی را در settings لوکال ذخیره میکند (can_edit=0).
|
||||
*
|
||||
* @param array<string, array<string, mixed>> $map
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Services;
|
||||
|
||||
use App\Http\Controllers\Admin\ZarinController;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Withdraw;
|
||||
use App\Models\Zarin;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
@@ -567,6 +568,29 @@ class ZarinSyncService
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* درخواست برداشت مشتری cash را مثبت ذخیره میکند (type=2) — علامت مبلغ برای جهت سند کافی نیست.
|
||||
* 0 = واریز، 1 = برداشت
|
||||
*/
|
||||
public function rialWalletDirectionFromWithdraw(Withdraw $withdraw): int
|
||||
{
|
||||
if ((int) ($withdraw->type ?? 0) === 2) {
|
||||
return 1;
|
||||
}
|
||||
$note = (string) ($withdraw->note ?? '');
|
||||
if ($note !== '' && str_contains($note, 'برداشت')) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ((float) ($withdraw->cash ?? 0)) >= 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
/** شرح محلی سند ریالی: «برداشت وجه» برداشت است؛ «واریز وجه» واریز. */
|
||||
public function rialWalletDirectionFromDesc(string $desc): int
|
||||
{
|
||||
return str_contains($desc, 'برداشت') ? 1 : 0;
|
||||
}
|
||||
|
||||
private function backfillWithdraw(ZarinController $controller, int $withdrawId): bool
|
||||
{
|
||||
$withdraw = \App\Models\Withdraw::query()->find($withdrawId);
|
||||
@@ -581,7 +605,7 @@ class ZarinSyncService
|
||||
$result = $controller->wallet([
|
||||
'customer_id' => (int) $withdraw->customer_id,
|
||||
'value' => abs($cash),
|
||||
'direction' => $cash >= 0 ? 0 : 1,
|
||||
'direction' => $this->rialWalletDirectionFromWithdraw($withdraw),
|
||||
'withdraw_id' => $withdrawId,
|
||||
'note' => $withdraw->note,
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user