[FEAT] 實作公共事業費逾期提醒、租戶自訂通知設定及發送測試信功能
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 56s
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 56s
This commit is contained in:
@@ -43,4 +43,55 @@ class SystemSettingController extends Controller
|
||||
|
||||
return redirect()->back()->with('success', '系統設定已更新');
|
||||
}
|
||||
|
||||
/**
|
||||
* 測試發送通知信
|
||||
*/
|
||||
public function testNotification(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'settings' => 'required|array',
|
||||
'settings.*.key' => 'required|string',
|
||||
'settings.*.value' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$settings = collect($validated['settings'])->pluck('value', 'key');
|
||||
|
||||
$senderEmail = $settings['notification.utility_fee_sender_email'] ?? null;
|
||||
$senderPassword = $settings['notification.utility_fee_sender_password'] ?? null;
|
||||
$recipientEmailsStr = $settings['notification.utility_fee_recipient_emails'] ?? null;
|
||||
|
||||
if (empty($senderEmail) || empty($senderPassword) || empty($recipientEmailsStr)) {
|
||||
return back()->with('error', '請先填寫完整發信帳號、密碼及收件者信箱。');
|
||||
}
|
||||
|
||||
// 動態覆寫應用程式名稱與 SMTP Config
|
||||
$tenantName = tenant('name') ?? config('app.name');
|
||||
config([
|
||||
'app.name' => $tenantName,
|
||||
'mail.mailers.smtp.username' => $senderEmail,
|
||||
'mail.mailers.smtp.password' => $senderPassword,
|
||||
'mail.from.address' => $senderEmail,
|
||||
'mail.from.name' => $tenantName . ' (系統通知)'
|
||||
]);
|
||||
|
||||
// 清理原先可能的 Mailer 實例,確保使用新的 Config
|
||||
\Illuminate\Support\Facades\Mail::purge();
|
||||
|
||||
// 解析收件者
|
||||
$recipients = array_map('trim', explode(',', $recipientEmailsStr));
|
||||
$validRecipients = array_filter($recipients, fn($e) => filter_var($e, FILTER_VALIDATE_EMAIL));
|
||||
|
||||
if (empty($validRecipients)) {
|
||||
return back()->with('error', '無效的收件者 Email 格式。');
|
||||
}
|
||||
|
||||
try {
|
||||
\Illuminate\Support\Facades\Mail::to($validRecipients)->send(new \App\Mail\TestNotificationMail());
|
||||
return back()->with('success', '測試信件已成功發送,請檢查收件匣。');
|
||||
} catch (\Exception $e) {
|
||||
return back()->with('error', '測試發信失敗: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ Route::middleware('auth')->group(function () {
|
||||
Route::middleware('permission:system.settings.view')->group(function () {
|
||||
Route::get('/settings', [SystemSettingController::class, 'index'])->name('settings.index');
|
||||
Route::post('/settings', [SystemSettingController::class, 'update'])->name('settings.update');
|
||||
Route::post('/settings/test-notification', [SystemSettingController::class, 'testNotification'])->name('settings.test-notification');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -34,13 +34,16 @@ class UtilityFeeController extends Controller
|
||||
public function store(Request $request)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'transaction_date' => 'required|date',
|
||||
'transaction_date' => 'nullable|date',
|
||||
'due_date' => 'required|date',
|
||||
'category' => 'required|string|max:255',
|
||||
'amount' => 'required|numeric|min:0',
|
||||
'invoice_number' => 'nullable|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$validated['payment_status'] = $this->determineStatus($validated);
|
||||
|
||||
$fee = UtilityFee::create($validated);
|
||||
|
||||
activity()
|
||||
@@ -55,13 +58,16 @@ class UtilityFeeController extends Controller
|
||||
public function update(Request $request, UtilityFee $utility_fee)
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'transaction_date' => 'required|date',
|
||||
'transaction_date' => 'nullable|date',
|
||||
'due_date' => 'required|date',
|
||||
'category' => 'required|string|max:255',
|
||||
'amount' => 'required|numeric|min:0',
|
||||
'invoice_number' => 'nullable|string|max:255',
|
||||
'description' => 'nullable|string',
|
||||
]);
|
||||
|
||||
$validated['payment_status'] = $this->determineStatus($validated);
|
||||
|
||||
$utility_fee->update($validated);
|
||||
|
||||
activity()
|
||||
@@ -73,6 +79,22 @@ class UtilityFeeController extends Controller
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判定繳費狀態
|
||||
*/
|
||||
private function determineStatus(array $data): string
|
||||
{
|
||||
if (!empty($data['transaction_date'])) {
|
||||
return UtilityFee::STATUS_PAID;
|
||||
}
|
||||
|
||||
if (!empty($data['due_date']) && now()->startOfDay()->gt(\Illuminate\Support\Carbon::parse($data['due_date']))) {
|
||||
return UtilityFee::STATUS_OVERDUE;
|
||||
}
|
||||
|
||||
return UtilityFee::STATUS_PENDING;
|
||||
}
|
||||
|
||||
public function destroy(UtilityFee $utility_fee)
|
||||
{
|
||||
activity()
|
||||
|
||||
@@ -10,26 +10,37 @@ class UtilityFee extends Model
|
||||
/** @use HasFactory<\Database\Factories\UtilityFeeFactory> */
|
||||
use HasFactory;
|
||||
|
||||
// 狀態常數
|
||||
const STATUS_PENDING = 'pending';
|
||||
const STATUS_PAID = 'paid';
|
||||
const STATUS_OVERDUE = 'overdue';
|
||||
|
||||
protected $fillable = [
|
||||
'transaction_date',
|
||||
'due_date',
|
||||
'category',
|
||||
'amount',
|
||||
'payment_status',
|
||||
'invoice_number',
|
||||
'description',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'transaction_date' => 'date:Y-m-d',
|
||||
'due_date' => 'date:Y-m-d',
|
||||
'amount' => 'decimal:2',
|
||||
];
|
||||
|
||||
public function tapActivity(\Spatie\Activitylog\Contracts\Activity $activity, string $eventName)
|
||||
{
|
||||
$activity->properties = $activity->properties->put('snapshot', [
|
||||
'transaction_date' => $this->transaction_date->format('Y-m-d'),
|
||||
$snapshot = [
|
||||
'transaction_date' => $this->transaction_date?->format('Y-m-d'),
|
||||
'due_date' => $this->due_date?->format('Y-m-d'),
|
||||
'category' => $this->category,
|
||||
'amount' => $this->amount,
|
||||
'payment_status' => $this->payment_status,
|
||||
'invoice_number' => $this->invoice_number,
|
||||
]);
|
||||
];
|
||||
$activity->properties = $activity->properties->put('snapshot', $snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user