Spaces:
Sleeping
Sleeping
Implement job deletion credit refunds
Browse filesAdded proper refund logic using CreditTransactionManager:
- Full refund if job never started (no third_party_id)
- Partial refund for queued jobs (reserves - 2 credits penalty)
- No refund for processing/completed jobs
- Full refund for failed jobs
All refunds properly tracked in credit_transactions table
with metadata about job type and status.
Resolves TODO at line 564.
- routers/gemini.py +55 -4
routers/gemini.py
CHANGED
|
@@ -561,11 +561,62 @@ async def delete_job(
|
|
| 561 |
detail="Job not found"
|
| 562 |
)
|
| 563 |
|
| 564 |
-
#
|
| 565 |
-
|
| 566 |
message = "Job deleted"
|
| 567 |
|
| 568 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 569 |
deleted = await qs.delete().soft_delete_one(job)
|
| 570 |
|
| 571 |
if not deleted:
|
|
@@ -577,7 +628,7 @@ async def delete_job(
|
|
| 577 |
return {
|
| 578 |
"success": True,
|
| 579 |
"message": message,
|
| 580 |
-
"refund_amount":
|
| 581 |
"new_credit_balance": user.credits
|
| 582 |
}
|
| 583 |
|
|
|
|
| 561 |
detail="Job not found"
|
| 562 |
)
|
| 563 |
|
| 564 |
+
# Implement credit refund via CreditTransactionManager
|
| 565 |
+
refund_amount = 0
|
| 566 |
message = "Job deleted"
|
| 567 |
|
| 568 |
+
# Determine refund based on job status
|
| 569 |
+
if job.credits_reserved > 0 and not job.credits_refunded:
|
| 570 |
+
from services.credit_service import CreditTransactionManager
|
| 571 |
+
|
| 572 |
+
if not job.third_party_id:
|
| 573 |
+
# Job never started (pre-execution failure)
|
| 574 |
+
refund_amount = job.credits_reserved
|
| 575 |
+
refund_reason = "Job deleted before execution"
|
| 576 |
+
|
| 577 |
+
elif job.status == "queued":
|
| 578 |
+
# Job queued - partial refund (2 credits cancellation fee)
|
| 579 |
+
penalty = 2
|
| 580 |
+
refund_amount = max(0, job.credits_reserved - penalty)
|
| 581 |
+
refund_reason = f"Job cancelled while queued (penalty: {penalty} credits)"
|
| 582 |
+
|
| 583 |
+
elif job.status in ["processing", "completed"]:
|
| 584 |
+
# No refund for started/completed jobs
|
| 585 |
+
refund_amount = 0
|
| 586 |
+
refund_reason = None
|
| 587 |
+
|
| 588 |
+
elif job.status == "failed":
|
| 589 |
+
# Failed job - full refund
|
| 590 |
+
refund_amount = job.credits_reserved
|
| 591 |
+
refund_reason = "Job failed - full refund"
|
| 592 |
+
|
| 593 |
+
# Process refund if applicable
|
| 594 |
+
if refund_amount > 0:
|
| 595 |
+
try:
|
| 596 |
+
await CreditTransactionManager.add_credits(
|
| 597 |
+
session=db,
|
| 598 |
+
user=user,
|
| 599 |
+
amount=refund_amount,
|
| 600 |
+
source="job_deletion",
|
| 601 |
+
reference_type="job",
|
| 602 |
+
reference_id=job.job_id,
|
| 603 |
+
reason=refund_reason,
|
| 604 |
+
metadata={
|
| 605 |
+
"job_type": job.job_type,
|
| 606 |
+
"original_cost": job.credits_reserved,
|
| 607 |
+
"job_status": job.status
|
| 608 |
+
}
|
| 609 |
+
)
|
| 610 |
+
|
| 611 |
+
job.credits_refunded = True
|
| 612 |
+
await db.commit()
|
| 613 |
+
message = f"Job deleted. {refund_amount} credits refunded."
|
| 614 |
+
|
| 615 |
+
except Exception as e:
|
| 616 |
+
logger.error(f"Failed to refund credits for job {job_id}: {e}")
|
| 617 |
+
message = "Job deleted (refund failed - contact support)"
|
| 618 |
+
|
| 619 |
+
# Soft delete the job
|
| 620 |
deleted = await qs.delete().soft_delete_one(job)
|
| 621 |
|
| 622 |
if not deleted:
|
|
|
|
| 628 |
return {
|
| 629 |
"success": True,
|
| 630 |
"message": message,
|
| 631 |
+
"refund_amount": refund_amount,
|
| 632 |
"new_credit_balance": user.credits
|
| 633 |
}
|
| 634 |
|