fix title

This commit is contained in:
2026-08-03 11:51:16 +03:30
parent ec0fd28efc
commit d360539208
14 changed files with 286 additions and 53 deletions
@@ -39,7 +39,7 @@ class GivePendingReferralGiftCommand extends Command
$already = TransactionsAdmin::where('customer_id', $customer->id)
->where('customer_to_id', $referrer->id)
->where('note', 'پاداش بابت معرفی')
->whereIn('note', \App\Http\Controllers\Controller::accountingReferralRewardDescAliases())
->exists();
if ($already) {
@@ -58,7 +58,7 @@ class GivePendingReferralGiftCommand extends Command
$given = TransactionsAdmin::where('customer_id', $customer->id)
->where('customer_to_id', $referrer->id)
->where('note', 'پاداش بابت معرفی')
->whereIn('note', \App\Http\Controllers\Controller::accountingReferralRewardDescAliases())
->exists();
if ($given) {
@@ -575,9 +575,11 @@ class TahesabController extends Controller
$customer = Customer::where('id', $data['customer_id'])->first();
}
$data['handler'] = 'wallet';
$isDeposit = (int) ($data['direction'] ?? 0) === 0;
$sharh = self::accountingWalletDesc($isDeposit, $data['note'] ?? null);
$tahesab = $existing ?? Tahesab::create([
"customer_id" => $customer->id,
"desc" => $data['direction'] == 0 ? "شارژ حساب" : "برداشت از حساب",
"desc" => $sharh,
"amount" => $data['value'],
"type" => "ريال",
"date" => Carbon::now(),
@@ -610,7 +612,7 @@ class TahesabController extends Controller
(int)$day,//Shamsi_Day
(int)$data['direction'],//IsDayaftAzMoshtariOrPardakhtBeMoshtari_0_1
(int)$data['value'],//Mablagh
$data['direction'] == 0 ? "شارژ حساب" : "برداشت از حساب",//Sharh
$sharh,//Sharh
(string)$this->Config('tahesab_bank_account'), //Name_Bank
"$tahesab->id",//Code_Rahgiri
-1,//Factor_Code
@@ -722,7 +724,7 @@ class TahesabController extends Controller
/**
* پاداش معرفی — همیشه روی حساب معرف (نه کاربر تازه‌ثبت‌نام‌شده).
*/
public function referrerGoldReward(Customer $invitedCustomer, float $gold, string $desc = 'پاداش بابت معرفی')
public function referrerGoldReward(Customer $invitedCustomer, float $gold, string $desc = 'پاداش معرفی')
{
$referrer = $invitedCustomer->referrer();
if (!$referrer) {
@@ -876,13 +878,10 @@ class TahesabController extends Controller
$isDeposit = (int) ($data['direction'] ?? 1) === 1;
$isVorood = $isDeposit ? 1 : 0;
$action = $isDeposit ? 'شارژ' : 'دشارژ';
$kindFa = $mapper->kindLabel($kind);
$sharh = !empty($data['note'])
? (string) $data['note']
: (!empty($data['desc'])
? (string) $data['desc']
: trim($title !== '' ? "{$action} {$title}" : "{$action} {$kindFa}"));
$sharh = self::accountingWalletDesc(
$isDeposit,
!empty($data['note']) ? (string) $data['note'] : (!empty($data['desc']) ? (string) $data['desc'] : null)
);
$data['note'] = $sharh;
$data['handler'] = 'walletGold';
@@ -1512,9 +1512,11 @@ class ZarinController extends Controller
}
$data['handler'] = 'wallet';
$isDeposit = (int) ($data['direction'] ?? 0) === 0;
$sharh = self::accountingWalletDesc($isDeposit, $data['note'] ?? null);
$zarin = $existing ?? Zarin::create([
'customer_id' => $customer->id,
'desc' => $data['direction'] == 0 ? 'شارژ حساب' : 'برداشت از حساب',
'desc' => $sharh,
'amount' => $data['value'],
'type' => 'ريال',
'date' => Carbon::now(),
@@ -1545,7 +1547,7 @@ class ZarinController extends Controller
'meghdar' => $data['value'],
'fi' => $mazaneh,
'hesab' => $customer->moshtari_code,
'sharh' => $data['direction'] == 0 ? 'شارژ حساب' : 'برداشت از حساب',
'sharh' => $sharh,
'ayar' => '750',
'movaghat' => '',
'idFactor' => '',
@@ -1584,7 +1586,7 @@ class ZarinController extends Controller
/**
* پاداش معرفی — همیشه روی حساب معرف (نه کاربر تازه‌ثبت‌نام‌شده).
*/
public function referrerGoldReward(Customer $invitedCustomer, float $gold, string $desc = 'پاداش بابت معرفی')
public function referrerGoldReward(Customer $invitedCustomer, float $gold, string $desc = 'پاداش معرفی')
{
$referrer = $invitedCustomer->referrer();
if (!$referrer) {
@@ -1744,12 +1746,10 @@ class ZarinController extends Controller
$vazn = $mapper->accountingWeight($product, $rawValue, $data);
$isDeposit = (int) ($data['direction'] ?? 1) === 1;
$title = $mapper->productTitle($product);
$action = $isDeposit ? 'شارژ' : 'دشارژ';
$sharh = !empty($data['note'])
? (string) $data['note']
: (!empty($data['desc'])
? (string) $data['desc']
: trim($title !== '' ? "{$action} {$title}" : "{$action} {$mapper->kindLabel($mapper->resolveKind($product))}"));
$sharh = self::accountingWalletDesc(
$isDeposit,
!empty($data['note']) ? (string) $data['note'] : (!empty($data['desc']) ? (string) $data['desc'] : null)
);
$data['note'] = $sharh;
$data['handler'] = 'walletGold';
$syncAmount = $mapper->isCountDoc($product) ? $count : $vazn;
+64
View File
@@ -345,6 +345,70 @@ class Controller extends BaseController
return 'برداشت ریالی';
}
/** شرح سند حسابداری برای واریز کیف (ریال/طلا) — پرگار، ته‌حساب، زرین */
public static function accountingDepositDesc(?string $note = null): string
{
return self::normalizeAccountingWalletNote($note, true);
}
/** شرح سند حسابداری برای برداشت کیف (ریال/طلا) — پرگار، ته‌حساب، زرین */
public static function accountingWithdrawDesc(?string $note = null): string
{
return self::normalizeAccountingWalletNote($note, false);
}
public static function accountingWalletDesc(bool $isDeposit, ?string $note = null): string
{
return $isDeposit
? self::accountingDepositDesc($note)
: self::accountingWithdrawDesc($note);
}
/**
* شرح سند کیف: پیش‌فرض «واریز»/«برداشت»؛
* note خاص (مثل پاداش معرفی یا توضیح ادمین) حفظ می‌شود؛
* عناوین عمومی واریز/برداشت/شارژ به همان دو کلمه نرمال می‌شوند.
*/
public static function normalizeAccountingWalletNote(?string $note, bool $isDeposit): string
{
$note = trim((string) $note);
if ($note === '') {
return $isDeposit ? 'واریز' : 'برداشت';
}
if (in_array($note, self::accountingReferralRewardDescAliases(), true)) {
return self::accountingReferralRewardDesc();
}
$generic = [
'واریز', 'برداشت',
'واریز ریالی', 'برداشت ریالی',
'واریز طلایی', 'برداشت طلایی',
'واریز درگاه', 'واریز آنلاین',
'واریز به کیف پول', 'برداشت از کیف پول',
'شارژ حساب', 'برداشت از حساب',
'شارژ', 'دشارژ',
'شارژ طلای کیف اصلی', 'برداشت طلای کیف اصلی',
];
if (in_array($note, $generic, true)) {
return $isDeposit ? 'واریز' : 'برداشت';
}
return $note;
}
/** شرح سند پاداش معرف — باید عین همین متن در همهٔ حسابداری‌ها برود */
public static function accountingReferralRewardDesc(): string
{
return 'پاداش معرفی';
}
/** عناوین قدیمی پاداش معرف برای idempotency / تشخیص دادهٔ قبلی */
public static function accountingReferralRewardDescAliases(): array
{
return ['پاداش معرفی', 'پاداش بابت معرفی'];
}
/**
* type و title تراکنش ریالی — بر اساس علامت cash (داده‌های قدیمی گاهی type=4 با cash مثبت دارند).
*/
@@ -702,13 +702,16 @@ class PargarInboundController extends Controller
$orderId = $withdrawId > 0 ? 'W-' . $withdrawId : 'WLOG-' . $log->id;
$isDeposit = $signed >= 0;
$note = trim((string) ($payload['note'] ?? ''));
$docDesc = self::accountingWalletDesc($isDeposit, $note !== '' ? $note : null);
// قرارداد پرگار (همان چیزی که سند سفارش هم با آن ساخته می‌شود):
// OrderType = 1 → سند «خرید» فروشگاه: وزن بدهکار، ریال بستانکار
// OrderType = -1 → سند «فروش» فروشگاه: وزن بستانکار، ریال بدهکار
// مانده در پرگار = بستانکار − بدهکار، پس برای اینکه شارژ در حساب مشتری مثبت بنشیند:
// شارژ طلای کیف اصلی → باید وزن بستانکار شود → OrderType = -1
// واریز ریالی → باید ریال بستانکار شود → OrderType = 1
// مانده در پرگار = بستانکار − بدهکار، پس برای اینکه واریز در حساب مشتری مثبت بنشیند:
// واریز طلای کیف اصلی → باید وزن بستانکار شود → OrderType = -1
// واریز ریالی → باید ریال بستانکار شود → OrderType = 1
// برچسب UI پرگار ممکن است همچنان «خرید/فروش پولی» بسازد؛ شرح ارسالی همیشه واریز/برداشت/پاداش است.
$orderType = $kind === 'gold'
? ($isDeposit ? -1 : 1)
: ($isDeposit ? 1 : -1);
@@ -727,7 +730,7 @@ class PargarInboundController extends Controller
'Weight' => abs($signed),
'Price' => 0,
'Carat' => 750,
'Description' => $isDeposit ? 'شارژ طلای کیف اصلی' : 'برداشت طلای کیف اصلی',
'Description' => $docDesc,
];
}
@@ -739,14 +742,14 @@ class PargarInboundController extends Controller
'PriceType' => 1,
'CustomerAccountId' => (int) ($customer->pargar_account_id ?? 0),
'ItemId' => $rialItemId > 0 ? $rialItemId : $sync->pargarItemIdGold(),
'ItemName' => $isDeposit ? 'واریز ریالی' : 'برداشت ریالی',
'ItemName' => $docDesc,
'OrderDate' => Jalalian::fromDateTime($log->date ?? $log->created_at)->format('Y/m/d-H:i:s'),
'Fee' => 0,
'Count' => 0,
'Weight' => 0,
'Price' => abs($signed),
'Carat' => 750,
'Description' => $isDeposit ? 'واریز ریالی' : 'برداشت ریالی',
'Description' => $docDesc,
];
}
}
+2 -2
View File
@@ -535,8 +535,8 @@ class PargarInboundWalletService
{
return match ($log->type) {
PargarSyncService::TYPE_ORDER => 'سفارش ' . $log->order_id,
PargarSyncService::TYPE_WALLET_GOLD => 'شارژ طلای کیف',
PargarSyncService::TYPE_WALLET_CASH => 'سند ریالی کیف',
PargarSyncService::TYPE_WALLET_GOLD => 'واریز/برداشت طلای کیف',
PargarSyncService::TYPE_WALLET_CASH => 'واریز/برداشت ریالی کیف',
default => (string) $log->type,
};
}
+3 -5
View File
@@ -204,11 +204,9 @@ class PargarSyncService
}
$isDeposit = $signedAmount > 0;
if ($kind === 'cash') {
$desc = $isDeposit ? 'واریز ریالی — ارسال به پرگار' : 'برداشت ریالی — ارسال به پرگار';
} else {
$desc = $isDeposit ? 'شارژ طلای کیف اصلی — ارسال به پرگار' : 'برداشت طلای کیف اصلی — ارسال به پرگار';
}
$note = isset($meta['note']) ? trim((string) $meta['note']) : '';
$docDesc = \App\Http\Controllers\Controller::accountingWalletDesc($isDeposit, $note !== '' ? $note : null);
$desc = $docDesc . ' — ارسال به پرگار';
$absAmount = abs($signedAmount);
// اگر هنوز مایگریشن widen اجرا نشده، مبلغ بزرگ را از همان اول در ستون نگذار
+19 -1
View File
@@ -57,6 +57,10 @@ TXT;
*/
public function scheduleBroadcastIfEligible(): void
{
if (! $this->hasPriceChannelAccess()) {
return;
}
if (! $this->config->getBool('price_channel_enabled', false)) {
return;
}
@@ -81,6 +85,10 @@ TXT;
public function broadcastIfEligible(): void
{
try {
if (! $this->hasPriceChannelAccess()) {
return;
}
if (! $this->config->getBool('price_channel_enabled', false)) {
return;
}
@@ -202,6 +210,10 @@ TXT;
public function broadcastAfterTemplateChange(): void
{
try {
if (! $this->hasPriceChannelAccess()) {
return;
}
if (! $this->config->getBool('price_channel_enabled', false)) {
return;
}
@@ -323,7 +335,7 @@ TXT;
'selected' => $isSelected,
'has_token' => $token !== '',
'destinations' => $chatIds,
'will_send' => $isSelected && $token !== '' && $chatIds !== [],
'will_send' => $this->hasPriceChannelAccess() && $isSelected && $token !== '' && $chatIds !== [],
];
}
@@ -333,6 +345,7 @@ TXT;
$display = $trade !== null ? $this->computeDisplayPrices() : null;
return [
'access' => $this->hasPriceChannelAccess(),
'enabled' => $this->config->getBool('price_channel_enabled', false),
'selected_messengers' => $selected,
'min_seconds' => $this->config->getInt('price_channel_min_seconds', 120),
@@ -850,6 +863,11 @@ TXT;
}
/** @return array<int, string> */
private function hasPriceChannelAccess(): bool
{
return $this->config->getBool('price_channel_access', false);
}
private function parseList(string $raw): array
{
$parts = preg_split('/[,\n]+/', trim($raw)) ?: [];
+104 -6
View File
@@ -9,6 +9,7 @@ use App\Models\Order;
use App\Models\Setting;
use App\Models\TransactionsAdmin;
use App\Models\Withdraw;
use Illuminate\Support\Facades\Log;
use Rooyesh\Wallet\interfaces\TransactionInterface;
use Rooyesh\Wallet\interfaces\WalletInterface;
use Rooyesh\Wallet\models\Transaction;
@@ -60,7 +61,7 @@ class ReferralGiftService
/**
* واریز معوق/دستی پاداش (مثلاً جبران وقتی گیت اشتباه جلوی واریز را گرفته).
* Idempotent — اگر قبلاً «پاداش بابت معرفی» خورده باشد دوباره نمی‌زند.
* Idempotent — اگر قبلاً «پاداش معرفی» (یا عنوان قدیمی) خورده باشد دوباره نمی‌زند.
*/
public function givePendingGifts(Customer $customer, bool $requireExistingOrder = false): void
{
@@ -128,7 +129,7 @@ class ReferralGiftService
{
return TransactionsAdmin::where('customer_id', $invited->id)
->where('customer_to_id', $referrer->id)
->where('note', 'پاداش بابت معرفی')
->whereIn('note', Controller::accountingReferralRewardDescAliases())
->exists();
}
@@ -139,6 +140,63 @@ class ReferralGiftService
->exists();
}
/**
* وقتی price_provider=montzar و کلید referral_gift_buy_from_montzar روشن است،
* قبل از واریز پاداش همان وزن از همکار خرید می‌شود.
* خاموش بودن کلید = روال قبلی (واریز محلی بدون خرید همکار).
* شکست خرید → واریز نمی‌شود (ثبت‌نام/سفارش خراب نمی‌شود؛ با givePendingGifts قابل جبران است).
*/
private function ensureMontzarCoverPurchase(
float $grams,
Customer $beneficiary,
string $reason,
ConfigService $config
): bool {
if (!$config->usesMontzarPricing()) {
return true;
}
if (!$config->getBool('referral_gift_buy_from_montzar', true)) {
return true;
}
if ($grams <= 0) {
return true;
}
$livePrice = (float) $config->Config('montzar_live_price');
$data = [
'amount' => $grams,
'direction' => 1, // خرید پوشش از همکار
'customer' => [
'name' => trim($reason . ' - ' . (string) ($beneficiary->name ?? '')),
],
'total_price' => (int) round($livePrice * $grams),
];
try {
$parsed = app(MontzarService::class)->submitOrder($data);
Log::info('Referral gift covered by Montzar buy', [
'grams' => $grams,
'reason' => $reason,
'beneficiary_id' => $beneficiary->id,
'provider_id' => $parsed['provider_id'] ?? null,
]);
return true;
} catch (\Throwable $e) {
report($e);
Log::error('Referral gift blocked: Montzar cover buy failed', [
'grams' => $grams,
'reason' => $reason,
'beneficiary_id' => $beneficiary->id,
'error' => $e->getMessage(),
]);
return false;
}
}
private function giveReferrerGift(
Customer $customer,
Customer $referrer,
@@ -147,6 +205,12 @@ class ReferralGiftService
string $companyUrl,
ConfigService $config
): void {
$rewardDesc = Controller::accountingReferralRewardDesc();
if (!$this->ensureMontzarCoverPurchase($giftForInviter, $referrer, $rewardDesc, $config)) {
return;
}
$withdraw = Withdraw::create([
'user_id' => $customer->id,
'customer_id' => $referrer->id,
@@ -161,7 +225,7 @@ class ReferralGiftService
'gold' => $giftForInviter,
'expire_at' => now(),
'active' => true,
'title' => 'پاداش بابت معرفی',
'title' => $rewardDesc,
'withdraw_id' => $withdraw->id,
'start_at' => now(),
], 8, true, false);
@@ -174,7 +238,7 @@ class ReferralGiftService
'wallet' => null,
'transaction_id' => $transaction->id,
'cash' => 0,
'note' => 'پاداش بابت معرفی',
'note' => $rewardDesc,
'type' => 1,
'gold' => $giftForInviter,
'balance_cash' => 0,
@@ -186,7 +250,7 @@ class ReferralGiftService
app(TahesabController::class)->referrerGoldReward(
$customer,
$giftForInviter,
'پاداش بابت معرفی'
$rewardDesc
);
} catch (\Exception $e) {
report($e);
@@ -198,13 +262,28 @@ class ReferralGiftService
app(\App\Http\Controllers\Admin\ZarinController::class)->referrerGoldReward(
$customer,
$giftForInviter,
'پاداش بابت معرفی'
$rewardDesc
);
} catch (\Exception $e) {
report($e);
}
}
try {
app(PargarSyncService::class)->queueWalletDocument(
$referrer,
'gold',
(float) $giftForInviter,
[
'withdraw_id' => $withdraw->id,
'note' => $rewardDesc,
'source' => 'referral_gift',
]
);
} catch (\Throwable $e) {
report($e);
}
$currentGold = Controller::formatSmsGoldWeight((float) $walletInterface->wallet->refresh()->gold);
$message = "سلام {$referrer->name} عزیز،\n\n{$giftForInviter} گرم طلا بابت معرفی {$customer->name} به حساب شما واریز شد.\nموجودی فعلی: {$currentGold} گرم.\n\nاطلاعات بیشتر: {$companyUrl}\n\nبا احترام،\n{$companyName}";
Controller::Send($referrer->mobile, $message);
@@ -217,6 +296,10 @@ class ReferralGiftService
string $companyUrl,
ConfigService $config
): void {
if (!$this->ensureMontzarCoverPurchase($giftForInvited, $customer, 'پاداش بابت ثبت نام', $config)) {
return;
}
$withdraw = Withdraw::create([
'user_id' => $customer->id,
'customer_id' => $customer->id,
@@ -275,6 +358,21 @@ class ReferralGiftService
}
}
try {
app(PargarSyncService::class)->queueWalletDocument(
$customer,
'gold',
(float) $giftForInvited,
[
'withdraw_id' => $withdraw->id,
'note' => 'پاداش بابت ثبت نام',
'source' => 'referral_register_gift',
]
);
} catch (\Throwable $e) {
report($e);
}
$currentGold = Controller::formatSmsGoldWeight((float) $walletInterface->wallet->refresh()->gold);
$message = "سلام {$customer->name} عزیز،\n\n{$giftForInvited} گرم طلا بابت ثبت نام به حساب شما واریز شد.\nموجودی فعلی: {$currentGold} گرم.\n\nاطلاعات بیشتر: {$companyUrl}\n\nبا احترام،\n{$companyName}";
Controller::Send($customer->mobile, $message);