Files
boursecu_server/app/Http/Controllers/Admin/MassageController.php
T

353 lines
11 KiB
PHP

<?php
namespace App\Http\Controllers\Admin;
use App\DB\Te\TableEngine;
use App\Models\Customer;
use App\Models\Message;
use App\Models\Order;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Services\ConfigService;
use App\Services\SmsProfanityFilter;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
class MassageController extends Controller
{
public function send_message(Request $request)
{
if (! app(ConfigService::class)->getBool('group_sms', false)) {
throw new UnprocessableEntityHttpException('پیامک گروهی غیرفعال است.');
}
$numbers = array_values(array_unique(array_filter(
array_map('strval', (array) ($request->numbers ?? [])),
static fn ($n) => trim($n) !== ''
)));
if ($numbers === []) {
throw new UnprocessableEntityHttpException('حداقل یک شماره لازم است.');
}
// هر درخواست حداکثر ۱۰ شماره — ادمین باید دسته‌ای بفرستد تا پنل پیامک زیر فشار نرود
if (count($numbers) > 10) {
throw new UnprocessableEntityHttpException('در هر درخواست حداکثر ۱۰ شماره مجاز است.');
}
// یافتن مشتریان با شماره‌های داده شده — فقط مشتریان پنل
$customers = Customer::whereIn('mobile', $numbers)
->where('type', 2)
->where('is_archive', false)
->get();
$known = $customers->pluck('mobile')->map(static fn ($m) => (string) $m)->all();
$unknown = array_values(array_diff($numbers, $known));
if ($unknown !== []) {
throw new UnprocessableEntityHttpException(
'فقط به مشتریان پنل می‌توان پیامک گروهی فرستاد. شماره خارج از لیست مشتری مجاز نیست.'
);
}
$filter = app(SmsProfanityFilter::class);
$filter->assertClean((string) ($request->message ?? ''));
foreach ($customers as $customer) {
// جایگزین کردن نام در پیام
$message = str_replace('%name%', $customer->name, $request->message);
// ارسال پیامک
$this->send($customer->mobile, $message);
}
return response()->json(true);
}
/**
* پیامک تکی به یک مشتری — فقط وقتی customer_direct_sms روشن باشد.
*/
public function send_customer_message(Request $request)
{
if (! app(ConfigService::class)->getBool('customer_direct_sms', false)) {
throw new UnprocessableEntityHttpException('ارسال پیامک تکی به مشتری غیرفعال است.');
}
$customerId = (int) ($request->input('customer_id') ?? 0);
$rawMessage = trim((string) ($request->input('message') ?? ''));
if ($customerId <= 0) {
throw new UnprocessableEntityHttpException('مشتری مشخص نشده است.');
}
if ($rawMessage === '') {
throw new UnprocessableEntityHttpException('متن پیامک خالی است.');
}
if (mb_strlen($rawMessage) > 700) {
throw new UnprocessableEntityHttpException('متن پیامک بیش از حد طولانی است.');
}
app(SmsProfanityFilter::class)->assertClean($rawMessage);
$customer = Customer::find($customerId);
if (! $customer || ! $customer->mobile) {
throw new UnprocessableEntityHttpException('مشتری یا شماره موبایل یافت نشد.');
}
$cfg = app(ConfigService::class);
$appName = (string) ($cfg->get('name_fa', '') ?: '');
$appUrl = $cfg->resolvePublicSiteUrl($request);
$message = str_replace(
['%name%', '%نام%', '%app_name%', '%نام_اپ%', '%app_url%', '%لینک_اپ%', '%لینک%'],
[
(string) $customer->name,
(string) $customer->name,
$appName,
$appName,
$appUrl,
$appUrl,
$appUrl,
],
$rawMessage
);
$this->send($customer->mobile, $message);
return response()->json(['ok' => true]);
}
public function getFunctionDescriptions()
{
return response()->json([
[
'function' => 'getAllCustomers',
'name' => 'همه کاربران',
],
[
'function' => 'getNoLoginCustomers',
'name' => 'کاربران وارد نشده',
],
[
'function' => 'getNoValidCustomers',
'name' => 'کاربران احراز نشده',
],
[
'function' => 'getActiveCustomers',
'name' => 'کاربران فعال',
],
[
'function' => 'getInactiveLast1Month',
'name' => 'یک ماه اخیر وارد نشده',
],
[
'function' => 'getInactiveLast3Months',
'name' => 'سه ماه اخیر وارد نشده',
],
[
'function' => 'getInactiveLast6Months',
'name' => 'شش ماه گذشته وارد نشده',
],
[
'function' => 'getInactiveLast1Year',
'name' => 'سال گذشته وارد نشده',
],
]);
}
public function getCustomerList(Request $request)
{
$customers = $this->resolveCustomersByFunctions((array) ($request->functions ?? []));
$uniqueCustomers = $this->removeDuplicateNumbers($customers);
return response()->json(['customers' => $uniqueCustomers]);
}
public function getCustomerListTable(Request $request)
{
$customers = $this->resolveCustomersByFunctions((array) ($request->functions ?? []));
$uniqueCustomers = $this->removeDuplicateNumbers($customers);
$uniqueCustomersCollection = collect($uniqueCustomers);
$records = Customer::whereIn('id', $uniqueCustomersCollection->pluck('id'));
// Initialize TableEngine
TableEngine::create($records, $request->all())
->initSearch(['customer.name'])
->select([
'id','mobile', 'name'
])
->export($records);
return response()->json($records);
}
/**
* @param list<string> $actions
* @return list<array{id:mixed,name:mixed,mobile:mixed}>
*/
private function resolveCustomersByFunctions(array $actions): array
{
$customers = [];
foreach ($actions as $action) {
$customers = array_merge($customers, match ($action) {
'getAllCustomers' => $this->getAllCustomers(),
'getNoLoginCustomers' => $this->getNoLoginCustomers(),
'getNoValidCustomers' => $this->getNoValidCustomers(),
'getActiveCustomers' => $this->getActiveCustomers(),
'getInactiveLast1Month' => $this->getInactiveSinceMonths(1),
'getInactiveLast3Months' => $this->getInactiveSinceMonths(3),
'getInactiveLast6Months' => $this->getInactiveSinceMonths(6),
'getInactiveLast1Year' => $this->getInactiveSinceMonths(12),
default => [],
});
}
return $customers;
}
private function getAllCustomers()
{
return Customer::where('type', 2)
->where('is_archive', false)
->get(['id', 'name', 'mobile'])
->toArray();
}
private function getNoLoginCustomers()
{
return Customer::where('type', 2)
->where('is_archive', false)
->whereNull('last_seen_at')
->get(['id', 'name', 'mobile'])
->toArray();
}
private function getNoValidCustomers()
{
return Customer::where('type', 2)
->where('is_archive', false)
->where('is_legal', 0)
->get(['id', 'name', 'mobile'])
->toArray();
}
private function getActiveCustomers()
{
return Customer::where('type', 2)
->where('is_archive', false)
->whereIn('id', function ($query) {
$query->select('owner')
->from('wallets');
})
->get(['id', 'name', 'mobile'])
->toArray();
}
/**
* مشتریان خانگی که در N ماه اخیر وارد نشده‌اند (یا هرگز وارد نشده‌اند).
*
* @return list<array{id:mixed,name:mixed,mobile:mixed}>
*/
private function getInactiveSinceMonths(int $months): array
{
$cutoff = now()->subMonths($months);
return Customer::where('type', 2)
->where('is_archive', false)
->where(function ($q) use ($cutoff) {
$q->whereNull('last_seen_at')
->orWhere('last_seen_at', '<', $cutoff);
})
->get(['id', 'name', 'mobile'])
->toArray();
}
private function removeDuplicateNumbers(array $customers)
{
$uniqueCustomers = [];
$seenNumbers = [];
foreach ($customers as $customer) {
if (!in_array($customer['mobile'], $seenNumbers)) {
$seenNumbers[] = $customer['mobile'];
$uniqueCustomers[] = $customer;
}
}
return $uniqueCustomers;
}
public function messagesTable(Request $request)
{
$records = Message::with(['person']);
$table = TableEngine::create($records, $request->all())
->initSearch([])
->select([
'id', 'sms', 'receiver','created_at',
]);
return response()->json($table->export());
}
/**
* Display a listing of the messages.
*/
public function index()
{
$messages = Message::all();
return response()->json($messages);
}
/**
* Store a newly created message in storage.
*/
public function store(Request $request)
{
$request->validate([
'sms' => 'required|string',
'receiver' => 'required|string',
]);
$message = Message::create($request->only(['sms', 'receiver']));
return response()->json($message, 201);
}
/**
* Display the specified message.
*/
public function show($id)
{
$message = Message::findOrFail($id);
return response()->json($message);
}
/**
* Update the specified message in storage.
*/
public function update(Request $request, $id)
{
$request->validate([
'sms' => 'sometimes|required|string',
'receiver' => 'sometimes|required|string',
]);
$message = Message::findOrFail($id);
$message->update($request->only(['sms', 'receiver']));
return response()->json($message);
}
/**
* Remove the specified message from storage.
*/
public function destroy($id)
{
$message = Message::findOrFail($id);
$message->delete();
return response()->json(null, 204);
}
}