dev #25
Binary file not shown.
144
server.py
144
server.py
@@ -1742,6 +1742,75 @@ async def get_my_event_activity(
|
|||||||
"total_rsvps": len(rsvps)
|
"total_rsvps": len(rsvps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Member Transaction History Endpoint
|
||||||
|
# ============================================================================
|
||||||
|
@api_router.get("/members/transactions")
|
||||||
|
async def get_member_transactions(
|
||||||
|
current_user: User = Depends(get_active_member),
|
||||||
|
db: Session = Depends(get_db)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Get current member's transaction history including subscriptions and donations.
|
||||||
|
Returns both types of transactions sorted by date (newest first).
|
||||||
|
"""
|
||||||
|
# Get user's subscriptions with plan details
|
||||||
|
subscriptions = db.query(Subscription).filter(
|
||||||
|
Subscription.user_id == current_user.id
|
||||||
|
).order_by(Subscription.created_at.desc()).all()
|
||||||
|
|
||||||
|
subscription_list = []
|
||||||
|
for sub in subscriptions:
|
||||||
|
plan = db.query(SubscriptionPlan).filter(SubscriptionPlan.id == sub.plan_id).first()
|
||||||
|
subscription_list.append({
|
||||||
|
"id": str(sub.id),
|
||||||
|
"type": "subscription",
|
||||||
|
"description": plan.name if plan else "Subscription",
|
||||||
|
"amount_cents": sub.amount_paid_cents or (sub.base_subscription_cents + sub.donation_cents),
|
||||||
|
"base_amount_cents": sub.base_subscription_cents,
|
||||||
|
"donation_cents": sub.donation_cents,
|
||||||
|
"status": sub.status.value if sub.status else "unknown",
|
||||||
|
"payment_method": sub.payment_method,
|
||||||
|
"card_brand": sub.card_brand,
|
||||||
|
"card_last4": sub.card_last4,
|
||||||
|
"stripe_receipt_url": sub.stripe_receipt_url,
|
||||||
|
"created_at": sub.created_at.isoformat() if sub.created_at else None,
|
||||||
|
"payment_completed_at": sub.payment_completed_at.isoformat() if sub.payment_completed_at else None,
|
||||||
|
"start_date": sub.start_date.isoformat() if sub.start_date else None,
|
||||||
|
"end_date": sub.end_date.isoformat() if sub.end_date else None,
|
||||||
|
"billing_cycle": plan.billing_cycle if plan else None,
|
||||||
|
"manual_payment": sub.manual_payment
|
||||||
|
})
|
||||||
|
|
||||||
|
# Get user's donations
|
||||||
|
donations = db.query(Donation).filter(
|
||||||
|
Donation.user_id == current_user.id
|
||||||
|
).order_by(Donation.created_at.desc()).all()
|
||||||
|
|
||||||
|
donation_list = []
|
||||||
|
for don in donations:
|
||||||
|
donation_list.append({
|
||||||
|
"id": str(don.id),
|
||||||
|
"type": "donation",
|
||||||
|
"description": "Donation",
|
||||||
|
"amount_cents": don.amount_cents,
|
||||||
|
"status": don.status.value if don.status else "unknown",
|
||||||
|
"payment_method": don.payment_method,
|
||||||
|
"card_brand": don.card_brand,
|
||||||
|
"card_last4": don.card_last4,
|
||||||
|
"stripe_receipt_url": don.stripe_receipt_url,
|
||||||
|
"created_at": don.created_at.isoformat() if don.created_at else None,
|
||||||
|
"payment_completed_at": don.payment_completed_at.isoformat() if don.payment_completed_at else None,
|
||||||
|
"notes": don.notes
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
"subscriptions": subscription_list,
|
||||||
|
"donations": donation_list,
|
||||||
|
"total_subscription_amount_cents": sum(s["amount_cents"] or 0 for s in subscription_list),
|
||||||
|
"total_donation_amount_cents": sum(d["amount_cents"] or 0 for d in donation_list)
|
||||||
|
}
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Calendar Export Endpoints (Universal iCalendar .ics format)
|
# Calendar Export Endpoints (Universal iCalendar .ics format)
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
@@ -2305,6 +2374,81 @@ async def get_user_by_id(
|
|||||||
"updated_at": user.updated_at.isoformat() if user.updated_at else None
|
"updated_at": user.updated_at.isoformat() if user.updated_at else None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@api_router.get("/admin/users/{user_id}/transactions")
|
||||||
|
async def get_user_transactions(
|
||||||
|
user_id: str,
|
||||||
|
db: Session = Depends(get_db),
|
||||||
|
current_user: User = Depends(require_permission("users.view"))
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Get a specific user's transaction history (admin only).
|
||||||
|
Returns subscriptions and donations for the specified user.
|
||||||
|
"""
|
||||||
|
# Verify user exists
|
||||||
|
user = db.query(User).filter(User.id == user_id).first()
|
||||||
|
if not user:
|
||||||
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
|
||||||
|
# Get user's subscriptions with plan details
|
||||||
|
subscriptions = db.query(Subscription).filter(
|
||||||
|
Subscription.user_id == user_id
|
||||||
|
).order_by(Subscription.created_at.desc()).all()
|
||||||
|
|
||||||
|
subscription_list = []
|
||||||
|
for sub in subscriptions:
|
||||||
|
plan = db.query(SubscriptionPlan).filter(SubscriptionPlan.id == sub.plan_id).first()
|
||||||
|
subscription_list.append({
|
||||||
|
"id": str(sub.id),
|
||||||
|
"type": "subscription",
|
||||||
|
"description": plan.name if plan else "Subscription",
|
||||||
|
"amount_cents": sub.amount_paid_cents or (sub.base_subscription_cents + sub.donation_cents),
|
||||||
|
"base_amount_cents": sub.base_subscription_cents,
|
||||||
|
"donation_cents": sub.donation_cents,
|
||||||
|
"status": sub.status.value if sub.status else "unknown",
|
||||||
|
"payment_method": sub.payment_method,
|
||||||
|
"card_brand": sub.card_brand,
|
||||||
|
"card_last4": sub.card_last4,
|
||||||
|
"stripe_receipt_url": sub.stripe_receipt_url,
|
||||||
|
"created_at": sub.created_at.isoformat() if sub.created_at else None,
|
||||||
|
"payment_completed_at": sub.payment_completed_at.isoformat() if sub.payment_completed_at else None,
|
||||||
|
"start_date": sub.start_date.isoformat() if sub.start_date else None,
|
||||||
|
"end_date": sub.end_date.isoformat() if sub.end_date else None,
|
||||||
|
"billing_cycle": plan.billing_cycle if plan else None,
|
||||||
|
"manual_payment": sub.manual_payment,
|
||||||
|
"manual_payment_notes": sub.manual_payment_notes
|
||||||
|
})
|
||||||
|
|
||||||
|
# Get user's donations
|
||||||
|
donations = db.query(Donation).filter(
|
||||||
|
Donation.user_id == user_id
|
||||||
|
).order_by(Donation.created_at.desc()).all()
|
||||||
|
|
||||||
|
donation_list = []
|
||||||
|
for don in donations:
|
||||||
|
donation_list.append({
|
||||||
|
"id": str(don.id),
|
||||||
|
"type": "donation",
|
||||||
|
"description": "Donation",
|
||||||
|
"amount_cents": don.amount_cents,
|
||||||
|
"status": don.status.value if don.status else "unknown",
|
||||||
|
"payment_method": don.payment_method,
|
||||||
|
"card_brand": don.card_brand,
|
||||||
|
"card_last4": don.card_last4,
|
||||||
|
"stripe_receipt_url": don.stripe_receipt_url,
|
||||||
|
"created_at": don.created_at.isoformat() if don.created_at else None,
|
||||||
|
"payment_completed_at": don.payment_completed_at.isoformat() if don.payment_completed_at else None,
|
||||||
|
"notes": don.notes
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
"user_id": str(user.id),
|
||||||
|
"user_name": f"{user.first_name} {user.last_name}",
|
||||||
|
"subscriptions": subscription_list,
|
||||||
|
"donations": donation_list,
|
||||||
|
"total_subscription_amount_cents": sum(s["amount_cents"] or 0 for s in subscription_list),
|
||||||
|
"total_donation_amount_cents": sum(d["amount_cents"] or 0 for d in donation_list)
|
||||||
|
}
|
||||||
|
|
||||||
@api_router.put("/admin/users/{user_id}")
|
@api_router.put("/admin/users/{user_id}")
|
||||||
async def update_user_profile(
|
async def update_user_profile(
|
||||||
user_id: str,
|
user_id: str,
|
||||||
|
|||||||
Reference in New Issue
Block a user