Финална имплементација на случаи на употреба
Трансфер на средства со email известување
User-to-User трансфер
Најавен корисник се навигира кон страницата за трансфер на средства и внесува email адреса на примачот.
Корисникот ги пополнува потребните информации и го кликнува копчето за испраќање.
По успешен трансфер, и испраќачот и примачот добиваат email известување со детали за трансакцијата.
Backend имплементација - views.py
При испраќање на трансфер преку POST барање, најпрво се валидира изворната сметка и балансот. Потоа се проверува дали примачот постои во системот.
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def transfer_funds(request):
data = request.data
source_account_id = data.get('source_account_id')
recipient_email = data.get('recipient_email')
amount = Decimal(str(data.get('amount', 0)))
note = data.get('note', '')
# Validate source account
source_account = Account.objects.get(id=source_account_id, user=request.user)
# Check balance
if source_account.balance < amount:
return Response({'error': 'Insufficient balance'})
По успешна валидација, се креираат две трансакции - една за испраќачот (debit) и една за примачот (credit):
with transaction.atomic():
Transaction.objects.create(
account=source_account,
transaction_type='debit',
amount=amount,
description=f'Sent to {recipient_user.first_name}'
)
Transaction.objects.create(
account=recipient_account,
transaction_type='credit',
amount=amount,
description=f'Received from {request.user.first_name}'
)
Email известување
По завршување на трансферот, се праќаат два email-и преку функцијата send_transfer_email:
def send_transfer_email(user, transfer_type, amount, recipient_name,
reference_number, new_balance, is_sender=True, note=None):
if is_sender:
subject = f'Banker - Transfer Sent: ${amount}'
else:
subject = f'Banker - Payment Received: ${amount}'
send_mail(
subject=subject,
message=message,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[user.email],
html_message=html_message
)
Email-от содржи: сума, име на примач/испраќач, референтен број, датум и време, нов баланс, и опционална порака (note) доколку е внесена при трансферот.
Internal трансфер (меѓу свои сметки)
Корисникот може да пренесе средства меѓу своите сметки.
При интерен трансфер, корисникот добива email со детали за двете сметки:
def send_internal_transfer_email(user, amount, from_account, to_account,
reference_number, from_balance, to_balance):
subject = f'Banker - Internal Transfer Completed: ${amount}'
# HTML email содржи табела со:
# - Amount
# - From Account (име на изворна сметка)
# - To Account (име на дестинациска сметка)
# - Updated Balances за двете сметки
Најава преку Google OAuth
Ненајавен корисник
Ненајавениот корисник се навигира кон страницата за најава.
Корисникот го кликнува копчето за најава преку Google профил и го селектира посакуваниот профил.
По успешна најава, корисникот е пренасочен кон главната страница.
Frontend имплементација - OAuthButtons.tsx
Во frontend делот се иницијализира Google Sign-In SDK и се рендерира официјалното Google копче:
useEffect(() => {
if (googleLoaded && window.google) {
window.google.accounts.id.initialize({
client_id: GOOGLE_CLIENT_ID,
callback: handleGoogleCallback,
ux_mode: 'popup',
});
window.google.accounts.id.renderButton(
googleButtonRef.current,
{ theme: 'outline', size: 'large', text: 'signin_with' }
);
}
}, [googleLoaded]);
По успешна автентикација, credential-от се праќа до backend-от:
const handleGoogleCallback = async (response) => {
const backendResponse = await fetch(
'http://localhost:8000/api/auth/google/',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ credential: response.credential })
}
);
const data = await backendResponse.json();
localStorage.setItem('access_token', data.access);
localStorage.setItem('user', JSON.stringify(data.user));
};
Backend имплементација - oauth_views.py
Во backend-от се верифицира Google credential преку Google tokeninfo endpoint:
@api_view(['POST'])
@permission_classes([AllowAny])
def google_login(request):
credential = request.data.get('credential')
# Verify token with Google
google_url = f'https://oauth2.googleapis.com/tokeninfo?id_token={credential}'
response = requests.get(google_url)
google_data = response.json()
# Verify audience matches our app
if google_data.get('aud') != settings.GOOGLE_CLIENT_ID:
return Response({'error': 'Token not for this app'})
email = google_data.get('email')
first_name = google_data.get('given_name', '')
last_name = google_data.get('family_name', '')
Доколку корисникот не постои, се креира нов:
user, created = User.objects.get_or_create(
email=email,
defaults={
'username': email,
'first_name': first_name,
'last_name': last_name,
}
)
# Generate JWT tokens
refresh = RefreshToken.for_user(user)
# Send login notification email
send_login_notification(user, 'Google Sign-in')
Email известување при најава
При секоја успешна најава преку Google, корисникот добива security email:
def send_login_notification(user, login_method):
subject = 'Banker - New Sign-in to Your Account'
# Email содржи:
# - Account email
# - Sign-in Method (Google Sign-in)
# - Date & Time
# - Security warning доколку не е корисникот
Support страница со email известување
Корисник испраќа support барање
Најавениот корисник се навигира кон Support страницата.
Корисникот пополнува форма со категорија, приоритет, предмет и порака.
По испраќање, корисникот добива потврда со ticket ID.
Frontend имплементација - support/page.tsx
Support формата содржи селекција за категорија и приоритет, како и полиња за предмет и порака:
const categories = [
{ value: 'general', label: 'General Inquiry', icon: HelpCircle },
{ value: 'bug', label: 'Bug Report', icon: Bug },
{ value: 'feature', label: 'Feature Request', icon: Lightbulb },
{ value: 'billing', label: 'Billing Issue', icon: CreditCard },
];
const priorities = [
{ value: 'low', label: 'Low', color: 'bg-gray-100' },
{ value: 'normal', label: 'Normal', color: 'bg-blue-100' },
{ value: 'high', label: 'High', color: 'bg-orange-100' },
{ value: 'urgent', label: 'Urgent', color: 'bg-red-100' },
];
При submit, се праќа POST барање до backend-от:
const handleSubmit = async (e) => {
const response = await fetch('http://localhost:8000/api/banking/support/', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ subject, message, category, priority }),
});
};
Backend имплементација - contact_views.py
Backend-от го обработува support барањето и праќа два email-и:
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def send_support_message(request):
data = request.data
user = request.user
subject = data.get('subject', 'Support Request')
message = data.get('message')
category = data.get('category', 'general')
priority = data.get('priority', 'normal')
# Generate unique ticket ID
ticket_id = f'TKT-{user.id}-{int(time.time())}'
Се праќаат два email-и:
[[Image(final13.png)]]
[[Image(final14.png)]]
# Email 1: To support team
send_mail(
subject=f'[Banker Support - {priority.upper()}] {subject}',
message=support_email_body,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[settings.SUPPORT_EMAIL],
)
# Email 2: Confirmation to user
send_mail(
subject=f'[Banker] Support Request Received - {ticket_id}',
message=user_confirmation,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[user.email],
)
Бришење на банкарска сметка
Корисник брише сметка
Најавениот корисник се навигира кон My Banks страницата.
Корисникот кликнува на копчето за бришење на сметка.
Системот прво проверува дали сметката има баланс - доколку има, не дозволува бришење.
Backend имплементација - views.py
@api_view(['DELETE'])
@permission_classes([IsAuthenticated])
def delete_account(request, account_id):
account = Account.objects.get(id=account_id, user=request.user)
# Check if account has balance
if account.balance > 0:
return Response({
'error': f'Cannot delete account with balance. Current: ${account.balance}'
}, status=status.HTTP_400_BAD_REQUEST)
# Delete all transactions for this account
Transaction.objects.filter(account=account).delete()
# Delete the account
account_name = f'{account.bank.name} {account.account_type.title()}'
account.delete()
return Response({
'message': f'Account "{account_name}" deleted successfully'
})
URL конфигурација - urls.py
path('accounts/<uuid:account_id>/', views.delete_account, name='delete_account'),
Филтрирање на аналитика по категорија
Корисник филтрира аналитика
Најавениот корисник се навигира кон Analytics страницата.
Корисникот може да филтрира по временски период и по категорија.
Backend имплементација - views.py
Analytics endpoint-от прима query параметри за филтрирање:
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def analytics_view(request):
# Get query parameters
date_range = request.GET.get('range', 'all')
category_filter = request.GET.get('category', 'all')
# Filter transactions by date
transactions = Transaction.objects.filter(account__in=user_accounts)
if start_date:
transactions = transactions.filter(created_at__gte=start_date)
# Filter by category if specified
if category_filter and category_filter != 'all':
transactions = transactions.filter(category__iexact=category_filter)
Филтрирањето се применува на сите калкулации - category breakdown, monthly trends и income vs expenses.
Исто така се враќа листа на достапни категории за dropdown менито:
# Get all available categories for filter dropdown
all_categories = list(Transaction.objects.filter(
account__in=user_accounts
).values_list('category', flat=True).distinct())
return Response({
'categoryBreakdown': category_breakdown,
'monthlyTrends': monthly_trends,
'incomeVsExpenses': income_vs_expenses,
'availableCategories': all_categories
})
Конфигурација на системот
Django Settings - settings.py
Email конфигурација за Gmail SMTP:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'smtp.gmail.com' EMAIL_PORT = 587 EMAIL_USE_TLS = True EMAIL_HOST_USER = 'tomislav.filevski@gmail.com' EMAIL_HOST_PASSWORD = 'не е внесено поради безбедносни причини' DEFAULT_FROM_EMAIL = 'Banker App <tomislav.filevski@gmail.com>' SUPPORT_EMAIL = 'tomislav.filevski@gmail.com'
Google OAuth конфигурација:
GOOGLE_CLIENT_ID = 'не е внесено поради безбедносни причини' GOOGLE_CLIENT_SECRET = 'не е внесено поради безбедносни причини'
URL Routing - urls.py
Authentication endpoints:
# authentication/urls.py
urlpatterns = [
path('google/', google_login, name='google_login'),
path('login/', login_view, name='login'),
path('register/', register_view, name='register'),
]
Banking endpoints:
# banking/urls.py
urlpatterns = [
path('transfer/', transfer_funds, name='transfer_funds'),
path('support/', send_support_message, name='support'),
path('analytics/', analytics_view, name='analytics'),
path('accounts/<uuid:account_id>/', delete_account, name='delete_account'),
]
Attachments (19)
- final1.png (135.3 KB ) - added by 5 days ago.
- final2.png (64.0 KB ) - added by 5 days ago.
- final3.png (25.1 KB ) - added by 5 days ago.
- final4.png (63.5 KB ) - added by 5 days ago.
- final5.png (72.8 KB ) - added by 5 days ago.
- final6.png (76.5 KB ) - added by 5 days ago.
- final9.png (63.6 KB ) - added by 5 days ago.
- final7.png (69.7 KB ) - added by 5 days ago.
- final8.png (119.5 KB ) - added by 5 days ago.
- final10.png (183.1 KB ) - added by 5 days ago.
- final11.png (83.6 KB ) - added by 5 days ago.
- final12.png (76.8 KB ) - added by 5 days ago.
- final13.png (99.4 KB ) - added by 5 days ago.
- final14.png (109.2 KB ) - added by 5 days ago.
- final15.png (92.9 KB ) - added by 5 days ago.
- final16.png (41.0 KB ) - added by 5 days ago.
- final17.png (165.0 KB ) - added by 5 days ago.
- final18.png (17.1 KB ) - added by 5 days ago.
- final19.png (119.3 KB ) - added by 5 days ago.
Download all attachments as: .zip
















