1.1
This commit is contained in:
parent
92ec45d230
commit
873880f7d1
Binary file not shown.
Binary file not shown.
@ -141,6 +141,9 @@ USE_TZ = True
|
|||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
||||||
|
|
||||||
|
MEDIA_URL = '/media/'
|
||||||
|
MEDIA_ROOT = BASE_DIR / 'media'
|
||||||
|
|
||||||
|
|
||||||
STATICFILES_DIRS = [
|
STATICFILES_DIRS = [
|
||||||
BASE_DIR / 'static',
|
BASE_DIR / 'static',
|
||||||
|
|||||||
@ -16,8 +16,13 @@ Including another URLconf
|
|||||||
"""
|
"""
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import include, path
|
from django.urls import include, path
|
||||||
|
from django.conf import settings
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("admin/", admin.site.urls),
|
path("admin/", admin.site.urls),
|
||||||
path("", include("core.urls")),
|
path("", include("core.urls")),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
if settings.DEBUG:
|
||||||
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.forms import UserCreationForm
|
from django.contrib.auth.forms import UserCreationForm
|
||||||
from .models import Company, Tender, Bid
|
from .models import Company, Tender, Bid, Document, Note, Approval
|
||||||
|
|
||||||
class SignUpForm(UserCreationForm):
|
class SignUpForm(UserCreationForm):
|
||||||
class Meta(UserCreationForm.Meta):
|
class Meta(UserCreationForm.Meta):
|
||||||
@ -20,3 +20,18 @@ class BidForm(forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Bid
|
model = Bid
|
||||||
fields = ['amount']
|
fields = ['amount']
|
||||||
|
|
||||||
|
class DocumentForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Document
|
||||||
|
fields = ['file', 'description']
|
||||||
|
|
||||||
|
class NoteForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Note
|
||||||
|
fields = ['note']
|
||||||
|
|
||||||
|
class ApprovalForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Approval
|
||||||
|
fields = ['status', 'comments']
|
||||||
|
|||||||
18
core/migrations/0002_document_description.py
Normal file
18
core/migrations/0002_document_description.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-11-15 18:57
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='document',
|
||||||
|
name='description',
|
||||||
|
field=models.TextField(blank=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
21
core/migrations/0003_document_uploaded_by.py
Normal file
21
core/migrations/0003_document_uploaded_by.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2025-11-15 18:58
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('core', '0002_document_description'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='document',
|
||||||
|
name='uploaded_by',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
||||||
Binary file not shown.
Binary file not shown.
@ -46,7 +46,9 @@ class Bid(models.Model):
|
|||||||
class Document(models.Model):
|
class Document(models.Model):
|
||||||
tender = models.ForeignKey(Tender, on_delete=models.CASCADE, null=True, blank=True)
|
tender = models.ForeignKey(Tender, on_delete=models.CASCADE, null=True, blank=True)
|
||||||
bid = models.ForeignKey(Bid, on_delete=models.CASCADE, null=True, blank=True)
|
bid = models.ForeignKey(Bid, on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
uploaded_by = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
|
||||||
file = models.FileField(upload_to='documents/')
|
file = models.FileField(upload_to='documents/')
|
||||||
|
description = models.TextField(blank=True)
|
||||||
uploaded_at = models.DateTimeField(auto_now_add=True)
|
uploaded_at = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|||||||
24
core/templates/core/approve_bid.html
Normal file
24
core/templates/core/approve_bid.html
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h1 class="card-title">Approve Bid</h1>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p><strong>Tender:</strong> {{ bid.tender.title }}</p>
|
||||||
|
<p><strong>Company:</strong> {{ bid.company.name }}</p>
|
||||||
|
<p><strong>Amount:</strong> ${{ bid.amount }}</p>
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<button type="submit" class="btn btn-primary">Submit Approval</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<a href="{% url 'tender_detail' bid.tender.id %}" class="btn btn-secondary">Back to Tender</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
19
core/templates/core/delete_bid.html
Normal file
19
core/templates/core/delete_bid.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h1 class="card-title">Delete Bid</h1>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>Are you sure you want to delete this bid of ${{ bid.amount }}?</p>
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" class="btn btn-danger">Delete</button>
|
||||||
|
<a href="{% url 'tender_detail' bid.tender.id %}" class="btn btn-secondary">Cancel</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
19
core/templates/core/delete_document.html
Normal file
19
core/templates/core/delete_document.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h1 class="card-title">Delete Document</h1>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>Are you sure you want to delete the document "{{ document.file.name }}"?</p>
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" class="btn btn-danger">Delete</button>
|
||||||
|
<a href="{% url 'tender_detail' document.tender.id %}" class="btn btn-secondary">Cancel</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
19
core/templates/core/delete_tender.html
Normal file
19
core/templates/core/delete_tender.html
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h1 class="card-title">Delete Tender</h1>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<p>Are you sure you want to delete the tender "{{ tender.title }}"?</p>
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" class="btn btn-danger">Delete</button>
|
||||||
|
<a href="{% url 'tender_detail' tender.id %}" class="btn btn-secondary">Cancel</a>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@ -14,10 +14,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
<div class="card-footer">
|
||||||
<a href="{% url 'tender_list' tender.company.id %}" class="btn btn-secondary">Back to Tenders</a>
|
<a href="{% url 'tender_list' tender.company.id %}" class="btn btn-secondary">Back to Tenders</a>
|
||||||
|
<a href="{% url 'update_tender' tender.id %}" class="btn btn-primary">Update</a>
|
||||||
|
<a href="{% url 'delete_tender' tender.id %}" class="btn btn-danger">Delete</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card mb-4">
|
||||||
<div class="card-header d-flex justify-content-between align-items-center">
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
<h2 class="h4">Bids</h2>
|
<h2 class="h4">Bids</h2>
|
||||||
<a href="{% url 'create_bid' tender.id %}" class="btn btn-primary">Create Bid</a>
|
<a href="{% url 'create_bid' tender.id %}" class="btn btn-primary">Create Bid</a>
|
||||||
@ -27,7 +29,23 @@
|
|||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
{% for bid in bids %}
|
{% for bid in bids %}
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
<span>{{ bid.company.name }} - ${{ bid.amount }}</span>
|
<div>
|
||||||
|
<span>{{ bid.company.name }} - ${{ bid.amount }}</span>
|
||||||
|
{% with approval=bid.approval_set.first %}
|
||||||
|
{% if approval %}
|
||||||
|
<span class="badge bg-{% if approval.status == 'approved' %}success{% elif approval.status == 'rejected' %}danger{% else %}secondary{% endif %}">{{ approval.get_status_display }}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="badge bg-secondary">Pending</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="{% url 'approve_bid' bid.id %}" class="btn btn-sm btn-outline-primary">Review</a>
|
||||||
|
{% if request.user.membership_set.first.company == bid.company %}
|
||||||
|
<a href="{% url 'update_bid' bid.id %}" class="btn btn-sm btn-outline-secondary">Update</a>
|
||||||
|
<a href="{% url 'delete_bid' bid.id %}" class="btn btn-sm btn-outline-danger">Delete</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
@ -36,5 +54,57 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="card mb-4">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2 class="h4">Documents</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="post" enctype="multipart/form-data" class="mb-4">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ doc_form.as_p }}
|
||||||
|
<button type="submit" name="submit_document" class="btn btn-primary">Upload Document</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if documents %}
|
||||||
|
<ul class="list-group">
|
||||||
|
{% for doc in documents %}
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<a href="{{ doc.file.url }}" target="_blank">{{ doc.file.name }}</a>
|
||||||
|
<small class="text-muted">by {{ doc.uploaded_by.username }} on {{ doc.uploaded_at|date:"Y-m-d" }}</small>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<p>No documents yet.</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h2 class="h4">Notes</h2>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="post" class="mb-4">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ note_form.as_p }}
|
||||||
|
<button type="submit" name="submit_note" class="btn btn-primary">Add Note</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% if notes %}
|
||||||
|
<ul class="list-group">
|
||||||
|
{% for note in notes %}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<p class="mb-1">{{ note.note }}</p>
|
||||||
|
<small class="text-muted">by {{ note.user.username }} on {{ note.created_at|date:"Y-m-d" }}</small>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<p>No notes yet.</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@ -10,8 +10,12 @@
|
|||||||
{% if tenders %}
|
{% if tenders %}
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
{% for tender in tenders %}
|
{% for tender in tenders %}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
<a href="{% url 'tender_detail' tender.id %}">{{ tender.title }}</a>
|
<a href="{% url 'tender_detail' tender.id %}">{{ tender.title }}</a>
|
||||||
|
<div>
|
||||||
|
<a href="{% url 'update_tender' tender.id %}" class="btn btn-sm btn-outline-primary">Update</a>
|
||||||
|
<a href="{% url 'delete_tender' tender.id %}" class="btn btn-sm btn-outline-danger">Delete</a>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
21
core/templates/core/update_bid.html
Normal file
21
core/templates/core/update_bid.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h1 class="card-title">Update Bid</h1>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<button type="submit" class="btn btn-primary">Update Bid</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<a href="{% url 'tender_detail' bid.tender.id %}" class="btn btn-secondary">Back to Tender</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
21
core/templates/core/update_tender.html
Normal file
21
core/templates/core/update_tender.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h1 class="card-title">Update Tender</h1>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<button type="submit" class="btn btn-primary">Update Tender</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
<a href="{% url 'tender_detail' tender.id %}" class="btn btn-secondary">Back to Tender</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@ -11,6 +11,11 @@ urlpatterns = [
|
|||||||
path('company/<int:company_id>/tenders/', views.tender_list, name='tender_list'),
|
path('company/<int:company_id>/tenders/', views.tender_list, name='tender_list'),
|
||||||
path('tender/<int:tender_id>/', views.tender_detail, name='tender_detail'),
|
path('tender/<int:tender_id>/', views.tender_detail, name='tender_detail'),
|
||||||
path('company/<int:company_id>/create_tender/', views.create_tender, name='create_tender'),
|
path('company/<int:company_id>/create_tender/', views.create_tender, name='create_tender'),
|
||||||
|
path('tender/<int:tender_id>/update/', views.update_tender, name='update_tender'),
|
||||||
|
path('tender/<int:tender_id>/delete/', views.delete_tender, name='delete_tender'),
|
||||||
path('tender/<int:tender_id>/create_bid/', views.create_bid, name='create_bid'),
|
path('tender/<int:tender_id>/create_bid/', views.create_bid, name='create_bid'),
|
||||||
|
path('bid/<int:bid_id>/update/', views.update_bid, name='update_bid'),
|
||||||
|
path('bid/<int:bid_id>/delete/', views.delete_bid, name='delete_bid'),
|
||||||
|
path('bid/<int:bid_id>/approve/', views.approve_bid, name='approve_bid'),
|
||||||
path('', views.home, name='home'),
|
path('', views.home, name='home'),
|
||||||
]
|
]
|
||||||
121
core/views.py
121
core/views.py
@ -1,8 +1,8 @@
|
|||||||
from django.shortcuts import render, redirect, get_object_or_404
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
from django.contrib.auth import login, authenticate, logout
|
from django.contrib.auth import login, authenticate, logout
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from .forms import SignUpForm, CompanyForm, TenderForm, BidForm
|
from .forms import SignUpForm, CompanyForm, TenderForm, BidForm, DocumentForm, NoteForm, ApprovalForm
|
||||||
from .models import Company, Membership, Tender, Bid
|
from .models import Company, Membership, Tender, Bid, Document, Note, Approval
|
||||||
|
|
||||||
def home(request):
|
def home(request):
|
||||||
return render(request, "core/index.html")
|
return render(request, "core/index.html")
|
||||||
@ -57,9 +57,37 @@ def tender_list(request, company_id):
|
|||||||
def tender_detail(request, tender_id):
|
def tender_detail(request, tender_id):
|
||||||
tender = get_object_or_404(Tender, pk=tender_id)
|
tender = get_object_or_404(Tender, pk=tender_id)
|
||||||
bids = Bid.objects.filter(tender=tender)
|
bids = Bid.objects.filter(tender=tender)
|
||||||
|
documents = Document.objects.filter(tender=tender)
|
||||||
|
notes = Note.objects.filter(tender=tender)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
if 'submit_document' in request.POST:
|
||||||
|
doc_form = DocumentForm(request.POST, request.FILES)
|
||||||
|
if doc_form.is_valid():
|
||||||
|
document = doc_form.save(commit=False)
|
||||||
|
document.tender = tender
|
||||||
|
document.uploaded_by = request.user
|
||||||
|
document.save()
|
||||||
|
return redirect('tender_detail', tender_id=tender.id)
|
||||||
|
elif 'submit_note' in request.POST:
|
||||||
|
note_form = NoteForm(request.POST)
|
||||||
|
if note_form.is_valid():
|
||||||
|
note = note_form.save(commit=False)
|
||||||
|
note.tender = tender
|
||||||
|
note.user = request.user
|
||||||
|
note.save()
|
||||||
|
return redirect('tender_detail', tender_id=tender.id)
|
||||||
|
|
||||||
|
doc_form = DocumentForm()
|
||||||
|
note_form = NoteForm()
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'tender': tender,
|
'tender': tender,
|
||||||
'bids': bids
|
'bids': bids,
|
||||||
|
'documents': documents,
|
||||||
|
'notes': notes,
|
||||||
|
'doc_form': doc_form,
|
||||||
|
'note_form': note_form
|
||||||
}
|
}
|
||||||
return render(request, 'core/tender_detail.html', context)
|
return render(request, 'core/tender_detail.html', context)
|
||||||
|
|
||||||
@ -81,6 +109,34 @@ def create_tender(request, company_id):
|
|||||||
}
|
}
|
||||||
return render(request, 'core/create_tender.html', context)
|
return render(request, 'core/create_tender.html', context)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def update_tender(request, tender_id):
|
||||||
|
tender = get_object_or_404(Tender, pk=tender_id)
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = TenderForm(request.POST, instance=tender)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
return redirect('tender_detail', tender_id=tender.id)
|
||||||
|
else:
|
||||||
|
form = TenderForm(instance=tender)
|
||||||
|
context = {
|
||||||
|
'form': form,
|
||||||
|
'tender': tender
|
||||||
|
}
|
||||||
|
return render(request, 'core/update_tender.html', context)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def delete_tender(request, tender_id):
|
||||||
|
tender = get_object_or_404(Tender, pk=tender_id)
|
||||||
|
if request.method == 'POST':
|
||||||
|
company_id = tender.company.id
|
||||||
|
tender.delete()
|
||||||
|
return redirect('tender_list', company_id=company_id)
|
||||||
|
context = {
|
||||||
|
'tender': tender
|
||||||
|
}
|
||||||
|
return render(request, 'core/delete_tender.html', context)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def create_bid(request, tender_id):
|
def create_bid(request, tender_id):
|
||||||
tender = get_object_or_404(Tender, pk=tender_id)
|
tender = get_object_or_404(Tender, pk=tender_id)
|
||||||
@ -108,3 +164,62 @@ def create_bid(request, tender_id):
|
|||||||
}
|
}
|
||||||
return render(request, 'core/create_bid.html', context)
|
return render(request, 'core/create_bid.html', context)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def update_bid(request, bid_id):
|
||||||
|
bid = get_object_or_404(Bid, pk=bid_id)
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = BidForm(request.POST, instance=bid)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
return redirect('tender_detail', tender_id=bid.tender.id)
|
||||||
|
else:
|
||||||
|
form = BidForm(instance=bid)
|
||||||
|
context = {
|
||||||
|
'form': form,
|
||||||
|
'bid': bid
|
||||||
|
}
|
||||||
|
return render(request, 'core/update_bid.html', context)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def delete_bid(request, bid_id):
|
||||||
|
bid = get_object_or_404(Bid, pk=bid_id)
|
||||||
|
if request.method == 'POST':
|
||||||
|
tender_id = bid.tender.id
|
||||||
|
bid.delete()
|
||||||
|
return redirect('tender_detail', tender_id=tender_id)
|
||||||
|
context = {
|
||||||
|
'bid': bid
|
||||||
|
}
|
||||||
|
return render(request, 'core/delete_bid.html', context)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def approve_bid(request, bid_id):
|
||||||
|
bid = get_object_or_404(Bid, pk=bid_id)
|
||||||
|
approval, created = Approval.objects.get_or_create(bid=bid, approver=request.user)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = ApprovalForm(request.POST, instance=approval)
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
return redirect('tender_detail', tender_id=bid.tender.id)
|
||||||
|
else:
|
||||||
|
form = ApprovalForm(instance=approval)
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'form': form,
|
||||||
|
'bid': bid
|
||||||
|
}
|
||||||
|
return render(request, 'core/approve_bid.html', context)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def delete_document(request, document_id):
|
||||||
|
document = get_object_or_404(Document, pk=document_id)
|
||||||
|
if request.method == 'POST':
|
||||||
|
tender_id = document.tender.id
|
||||||
|
document.delete()
|
||||||
|
return redirect('tender_detail', tender_id=tender_id)
|
||||||
|
context = {
|
||||||
|
'document': document
|
||||||
|
}
|
||||||
|
return render(request, 'core/delete_document.html', context)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user