feat: add domain registration form and email notifications

- Create a new Blade view for domain registration (`registrant-tochuc.blade.php`) to capture organization and manager details.
- Implement email templates for new domain orders for both admin (`domain-order-new.blade.php`) and customers (`domain-order-received.blade.php`).
- Add CSV exports for client and domain data.
- Introduce tests for customer mass assignment, password reset, login throttling, and permission gating.
- Ensure service renewals use current pricing and validate ownership for virtual machines.
- Validate mass assignment behavior in service model.
This commit is contained in:
baodev0
2026-08-22 17:30:55 +07:00
parent eec2c5906e
commit c377c7e195
58 changed files with 3063 additions and 418 deletions
+14 -4
View File
@@ -17,14 +17,17 @@ use App\Models\OrderItem;
use App\Models\Service;
use App\Models\VirtualMachines;
use App\Repositories\Api\Order\OrderRepository;
use App\Repositories\Api\Service\ServiceRepositoryInterface;
use Carbon\Carbon;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
class OrderQueryService
{
public function __construct(private readonly OrderRepository $orderRepository)
{
public function __construct(
private readonly OrderRepository $orderRepository,
private readonly ServiceRepositoryInterface $productRepo,
) {
}
public function getOrdersForCustomer(int $customerId, ClientOrderFilters $filters): LengthAwarePaginator
@@ -198,11 +201,18 @@ class OrderQueryService
}
$orderItem = $service->orderItem;
if (! $orderItem || (int) $orderItem->price <= 0) {
if (! $orderItem) {
return ['ok' => false, 'message' => 'Không thể xác định giá gia hạn dịch vụ.', 'code' => 400];
}
$price = (int) $orderItem->price * $months;
// Gia hạn luôn dùng giá sản phẩm hiện tại trong bảng giá, không dùng giá đã
// chốt lúc đặt mua ban đầu — giá cũ chỉ để hiển thị trên đơn hàng/hoá đơn gốc.
$currentPrice = $this->productRepo->getPricing((int) $service->product_id, $orderItem->billing_cycle);
if ($currentPrice === null) {
return ['ok' => false, 'message' => 'Sản phẩm hiện không còn bán, không thể gia hạn.', 'code' => 400];
}
$price = (int) $currentPrice * $months;
if ($service->invoice_id && Invoice::where('id', $service->invoice_id)
->where('invoice_type', 2)