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:
baodev0
2026-10-22 22:22:09 +07:00
co-authored by Claude Opus 5.5
parent 02daefe4c2
commit fe68171aa7
15 changed files with 281 additions and 40 deletions
@@ -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();