feat(services): partial/unpaid payment on admin create, payment history per invoice, zip attachments
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
02daefe4c2
commit
fe68171aa7
@@ -215,8 +215,10 @@ trait ManagesCustomerServices
|
||||
'expires_at' => 'nullable|date',
|
||||
'note' => 'nullable|string',
|
||||
'billing_cycle' => ['nullable', Rule::in(BillingCycleCatalog::codes())],
|
||||
'payment_method' => 'required|in:transfer,balance',
|
||||
'amount_paid' => 'nullable|numeric|min:0',
|
||||
'price' => 'nullable|numeric|min:0',
|
||||
'payment_status' => 'nullable|in:paid,partial,unpaid',
|
||||
'payment_method' => 'required_unless:payment_status,unpaid|nullable|in:transfer,balance',
|
||||
'amount_paid' => 'required_if:payment_status,partial|nullable|numeric|gt:0',
|
||||
'proof_images' => 'nullable|array',
|
||||
'proof_images.*' => 'file|image|max:5120',
|
||||
'os_id' => 'nullable|integer|exists:os,id',
|
||||
@@ -230,8 +232,12 @@ trait ManagesCustomerServices
|
||||
'vm_port' => 'nullable|integer|min:1|max:65535',
|
||||
]);
|
||||
|
||||
// Upload proof images (chuyển khoản) — I/O ở tầng HTTP, service chỉ nhận đường dẫn đã lưu.
|
||||
if ($data['payment_method'] === 'transfer' && $request->hasFile('proof_images')) {
|
||||
$data['payment_status'] ??= 'paid';
|
||||
if ($data['payment_status'] === 'unpaid') {
|
||||
$data['payment_method'] = null;
|
||||
}
|
||||
|
||||
if (($data['payment_method'] ?? null) === 'transfer' && $request->hasFile('proof_images')) {
|
||||
$data['_proof_paths'] = collect($request->file('proof_images'))
|
||||
->map(fn($file) => $file->store('payment-proofs', 'public'))
|
||||
->all();
|
||||
|
||||
@@ -28,7 +28,7 @@ trait HandlesServiceAttachments
|
||||
public function uploadAttachment(Request $request, int $id): JsonResponse
|
||||
{
|
||||
Service::findOrFail($id);
|
||||
$request->validate(['file' => InvoiceAttachment::UPLOAD_RULE]);
|
||||
$request->validate(['file' => ServiceAttachment::UPLOAD_RULE]);
|
||||
|
||||
$file = $request->file('file');
|
||||
$attachment = ServiceAttachment::create([
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Http\Controllers\Controller;
|
||||
use App\Jobs\VirtualMachine\Provision\ResendVmCredentialsEmailJob;
|
||||
use App\Models\ActivityLog;
|
||||
use App\Models\DomainPricing;
|
||||
use App\Support\Billing\InvoicePaymentHistory;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\ModuleVmware;
|
||||
use App\Models\Service;
|
||||
@@ -93,7 +94,10 @@ class ServiceController extends Controller
|
||||
|
||||
ModuleVmware::resolveVirtualMachineIds([$service->vmware]);
|
||||
|
||||
$service->setAttribute('linked_invoices', $this->linkedInvoices(collect([$service])));
|
||||
$invoices = $this->linkedInvoices(collect([$service]));
|
||||
$payments = InvoicePaymentHistory::forInvoices($invoices);
|
||||
$invoices->each(fn (Invoice $invoice) => $invoice->setAttribute('payments', $payments[$invoice->id]));
|
||||
$service->setAttribute('linked_invoices', $invoices);
|
||||
$service->setAttribute('activity_logs', ActivityLog::where('subject_type', Service::class)
|
||||
->where('subject_id', $service->id)
|
||||
->latest('id')
|
||||
@@ -109,7 +113,7 @@ class ServiceController extends Controller
|
||||
return Invoice::ofServices($services)
|
||||
->with('order:id,order_num')
|
||||
->latest('id')
|
||||
->get(['id', 'order_id', 'service_id', 'invoice_number', 'invoice_type', 'status', 'total', 'created_at']);
|
||||
->get(['id', 'customer_id', 'order_id', 'service_id', 'invoice_number', 'invoice_type', 'status', 'total', 'amount_paid', 'due_date', 'created_at']);
|
||||
}
|
||||
|
||||
public function bulkAction(Request $request): JsonResponse
|
||||
|
||||
Reference in New Issue
Block a user