浏览代码

added tender allocation per record

jacob-kruger-work 1 月之前
父节点
当前提交
76f2e7652d

+ 23 - 1
flask_app/app/main/forms.py

@@ -61,7 +61,7 @@ class RoleDepartmentForm(FlaskForm):
 
 
 
 
 class RoleForm(FlaskForm):
 class RoleForm(FlaskForm):
-    hid_role_id = HiddenField(id="hid_qualification_id", default="0")
+    hid_role_id = HiddenField(id="hid_role_id", default="0")
     sel_department = SelectField(id="sel_departmen", label="Department", choices=[(0, "IT and Technology"), (1, "Sales and Marketing")], default=0)
     sel_department = SelectField(id="sel_departmen", label="Department", choices=[(0, "IT and Technology"), (1, "Sales and Marketing")], default=0)
     txt_role_name = StringField(id="txt_role_name", label="Role Name", validators=[InputRequired(), Length(min=3, max=128)])
     txt_role_name = StringField(id="txt_role_name", label="Role Name", validators=[InputRequired(), Length(min=3, max=128)])
     txt_description = TextAreaField(id="txt_description", label="Description", validators=[Length(min=0, max=255)], render_kw={"wrap": "hard", "rows": "5", "cols": "50"})
     txt_description = TextAreaField(id="txt_description", label="Description", validators=[Length(min=0, max=255)], render_kw={"wrap": "hard", "rows": "5", "cols": "50"})
@@ -71,6 +71,7 @@ class RoleDepartmentRemovalForm(FlaskForm):
     hid_remove_department_id = HiddenField(id="hid_remove_department_id", default="0")
     hid_remove_department_id = HiddenField(id="hid_remove_department_id", default="0")
 # end of RoleDepartmentRemovalForm class
 # end of RoleDepartmentRemovalForm class
 
 
+
 class RoleRemovalForm(FlaskForm):
 class RoleRemovalForm(FlaskForm):
     hid_remove_role_id = HiddenField(id="hid_remove_role_id", default="0")
     hid_remove_role_id = HiddenField(id="hid_remove_role_id", default="0")
 # end of RoleRemovalForm class
 # end of RoleRemovalForm class
@@ -120,3 +121,24 @@ class UserForm(FlaskForm):
 class UserRemovalForm(FlaskForm):
 class UserRemovalForm(FlaskForm):
     hid_remove_user_id = HiddenField(id="hid_remove_user_id", default="0")
     hid_remove_user_id = HiddenField(id="hid_remove_user_id", default="0")
 # end of UserRemovalForm class
 # end of UserRemovalForm class
+
+
+class TenderForm(FlaskForm):
+    hid_tender_id = HiddenField(id="hid_tender_id", default="0")
+    txt_reference_number = StringField(id="txt_reference_number", label="Reference Number", validators=[InputRequired(), Length(min=1, max=64)])
+    txt_description = TextAreaField(id="txt_description", label="Description", validators=[Length(min=0, max=512)], render_kw={"wrap": "hard", "rows": "5", "cols": "50"})
+# end of TenderForm class
+
+
+class TenderRemovalForm(FlaskForm):
+    hid_remove_tender_id = HiddenField(id="hid_remove_tender_id", default="0")
+# end of TenderRemovalForm class
+
+
+class TenderAllocationForm(FlaskForm):
+    sel_tender = SelectField(id="sel_tender", label="Tender to be Allocated", choices=[(0, "---none---")], default=0)
+# end of TenderAllocationForm class
+
+class TenderCVRemovalForm(FlaskForm):
+    hid_tender_cv_id = HiddenField(id="hid_tender_cv_id", default="0")
+# end of TenderCVRemovalForm class

+ 136 - 7
flask_app/app/main/routes.py

@@ -10,7 +10,7 @@ from sqlalchemy import and_, or_, not_, func
 import json, requests, re, os
 import json, requests, re, os
 from .forms import RecordForm, QualificationTypeForm, QualificationForm, QualificationTypeRemovalForm, QualificationRemovalForm, RecordQualificationForm, RecordQualificationRemovalForm
 from .forms import RecordForm, QualificationTypeForm, QualificationForm, QualificationTypeRemovalForm, QualificationRemovalForm, RecordQualificationForm, RecordQualificationRemovalForm
 from .forms import RoleDepartmentForm, RoleForm, RoleDepartmentRemovalForm, RoleRemovalForm, \
 from .forms import RoleDepartmentForm, RoleForm, RoleDepartmentRemovalForm, RoleRemovalForm, \
-    UploadForm, UploadRemovalForm, FilterForm
+    UploadForm, UploadRemovalForm, FilterForm, TenderForm, TenderRemovalForm, TenderAllocationForm, TenderCVRemovalForm
 from .forms import UserForm, UserRemovalForm
 from .forms import UserForm, UserRemovalForm
 import re
 import re
 import datetime as datetime_class
 import datetime as datetime_class
@@ -145,6 +145,7 @@ def index():
     # end of surrounding try-except
     # end of surrounding try-except
 # end of index view function for route /
 # end of index view function for route /
 
 
+
 @bp.route("/icons", methods=["GET"])
 @bp.route("/icons", methods=["GET"])
 def icons():
 def icons():
     """icons preview - purely testing"""
     """icons preview - purely testing"""
@@ -177,6 +178,8 @@ def capture_record(i_record:int = 0):
                 qualification_form.sel_qualification.choices = l_choices
                 qualification_form.sel_qualification.choices = l_choices
             # end of checking if qualifications were retrieved
             # end of checking if qualifications were retrieved
         # end of checking if there are qualification types
         # end of checking if there are qualification types
+        tender_form = TenderAllocationForm()
+        tender_removal_form = TenderCVRemovalForm()
         if form.validate_on_submit() and request.form.get("btn_save", "")=="Save":
         if form.validate_on_submit() and request.form.get("btn_save", "")=="Save":
             s_action = "updated"
             s_action = "updated"
             o_record = None
             o_record = None
@@ -258,9 +261,36 @@ def capture_record(i_record:int = 0):
                 db.session.commit()
                 db.session.commit()
                 flash("Qualification removed")
                 flash("Qualification removed")
             # end of making sure retrieved record
             # end of making sure retrieved record
-        # end of checking for form submission
+        elif tender_removal_form.validate_on_submit() and request.form.get("hid_tender_cv_id", None) is not None:
+            i_tender_cv_id = int(tender_removal_form.hid_tender_cv_id.data)
+            db.session.execute(delete(tbl_tender_cvs).where(tbl_tender_cvs.id==i_tender_cv_id))
+            db.session.commit()
+            flash("Tender allocation removed", "success")
+        # end of checking for form submission initially
+        # populate possible tender allocation choices
+        sq_tenders = select(tbl_tender_cvs.i_tender_id.distinct()).filter(tbl_tender_cvs.i_record_id==i_record)
+        l_other_tenders = list(map(dict_row, db.session.query(tbl_tenders.id, tbl_tenders.v_reference_number, tbl_tenders.v_description).filter(tbl_tenders.id.not_in(sq_tenders)).all()))
+        if len(l_other_tenders)>0:
+            l_tender_choices = []
+            for ix, d_tender in enumerate(l_other_tenders):
+                l_tender_choices.append((d_tender["id"], " - ".join((d_tender["v_reference_number"], str(d_tender["v_description"])[:20]))))
+            # end of looping through other tenders
+            tender_form.sel_tender.choices = tender_form.sel_tender.choices + l_tender_choices
+        # end of checking if need to populate tender choices for possible allocation
+        # second form submission check after cv allocation might have been updated - because am populating tender choices here b4 validation
+        if tender_form.validate_on_submit() and request.form.get("btn_allocate", "")=="Allocate":
+            i_tender_id = int(tender_form.sel_tender.data)
+            if i_tender_id>0:
+                db.session.add(tbl_tender_cvs(i_tender_id=i_tender_id, i_record_id=i_record))
+                db.session.commit()
+                flash("Tender allocated", "success")
+                # update tender allocation choices
+                tender_form.sel_tender.choices = list(filter((lambda x : x[0]!=i_tender_id), tender_form.sel_tender.choices))
+            # end of making sure actual tender record was selected
+        # end of second form submission check
         form.hid_record_id.data = i_record
         form.hid_record_id.data = i_record
         remove_qualification_form.hid_remove_qualification_id.data = 0
         remove_qualification_form.hid_remove_qualification_id.data = 0
+        tender_form.sel_tender.data = 0
         # populate record info if existing record
         # populate record info if existing record
         if i_record>0:
         if i_record>0:
             o_record = db.session.get(tbl_records, i_record)
             o_record = db.session.get(tbl_records, i_record)
@@ -288,9 +318,13 @@ def capture_record(i_record:int = 0):
         l_languages = db.session.query(tbl_languages.v_language_abbreviation, tbl_languages.v_language_name, tbl_languages.si_level).filter(tbl_languages.i_record_id==i_record).order_by(tbl_languages.si_ranking).all()
         l_languages = db.session.query(tbl_languages.v_language_abbreviation, tbl_languages.v_language_name, tbl_languages.si_level).filter(tbl_languages.i_record_id==i_record).order_by(tbl_languages.si_ranking).all()
         l_languages = list(map(dict_row, l_languages))
         l_languages = list(map(dict_row, l_languages))
         l_record_qualifications = list(map(dict_row, db.session.query(tbl_record_qualifications.id, tbl_qualification_types.v_qualification_type, tbl_qualifications.v_qualification_name, tbl_record_qualifications.d_acquired).join(tbl_qualifications, tbl_record_qualifications.i_qualification_id==tbl_qualifications.id, isouter=False).join(tbl_qualification_types, tbl_qualifications.i_qualification_type==tbl_qualification_types.id, isouter=False).filter(tbl_record_qualifications.i_record_id==i_record).order_by(tbl_record_qualifications.d_acquired, tbl_qualifications.v_qualification_name).all()))
         l_record_qualifications = list(map(dict_row, db.session.query(tbl_record_qualifications.id, tbl_qualification_types.v_qualification_type, tbl_qualifications.v_qualification_name, tbl_record_qualifications.d_acquired).join(tbl_qualifications, tbl_record_qualifications.i_qualification_id==tbl_qualifications.id, isouter=False).join(tbl_qualification_types, tbl_qualifications.i_qualification_type==tbl_qualification_types.id, isouter=False).filter(tbl_record_qualifications.i_record_id==i_record).order_by(tbl_record_qualifications.d_acquired, tbl_qualifications.v_qualification_name).all()))
+        l_prior_tenders = list(map(dict_row, db.session.query(tbl_tender_cvs.id, tbl_tenders.v_reference_number, tbl_tenders.v_description, tbl_tender_cvs.dt_when).join(tbl_tenders, tbl_tenders.id==tbl_tender_cvs.i_tender_id, isouter=False).filter(tbl_tender_cvs.i_record_id==i_record).order_by(tbl_tender_cvs.dt_when.desc()).limit(3)))
+        for ix, t in enumerate(l_prior_tenders):
+            l_prior_tenders[ix]["dt_when"] = l_prior_tenders[ix]["dt_when"].strftime("%Y-%m-%d %H:%M")
+        # end of updating values in prior tenders
         s_base = "base_bs.html" if Config.BOOTSTRAP else "base.html"
         s_base = "base_bs.html" if Config.BOOTSTRAP else "base.html"
         s_url = url_for("main.capture_record")#, _external=True)
         s_url = url_for("main.capture_record")#, _external=True)
-        return render_template("capture_record.html", js=True, base=s_base, url=s_url, form=form, record_id=i_record, languages=l_languages, all_languages=l_all_languages, qualification_types=l_qualification_types, qualification_form=qualification_form, record_qualifications=l_record_qualifications, departments=l_departments, roles=l_roles, department_id=i_department_id, role_id=i_role_id, remove_qualification_form=remove_qualification_form)
+        return render_template("capture_record.html", js=True, base=s_base, url=s_url, form=form, record_id=i_record, languages=l_languages, all_languages=l_all_languages, qualification_types=l_qualification_types, qualification_form=qualification_form, record_qualifications=l_record_qualifications, departments=l_departments, roles=l_roles, department_id=i_department_id, role_id=i_role_id, remove_qualification_form=remove_qualification_form, prior_tenders=l_prior_tenders, tender_form=tender_form, remove_tender_form=tender_removal_form)
     except Exception as exc:
     except Exception as exc:
         return render_template_string(end_user_debugging("capture_record"))
         return render_template_string(end_user_debugging("capture_record"))
     # end of surrounding try-except
     # end of surrounding try-except
@@ -560,7 +594,7 @@ def roles():
     except Exception as exc:
     except Exception as exc:
         return render_template_string(end_user_debugging("roles"))
         return render_template_string(end_user_debugging("roles"))
     # end of surrounding try-except
     # end of surrounding try-except
-# end of roles view function for route /positions
+# end of roles view function for route /roles
 
 
 
 
 @bp.route("/roles_list/<int:i_department_id>/", methods=["GET"])
 @bp.route("/roles_list/<int:i_department_id>/", methods=["GET"])
@@ -686,6 +720,7 @@ def record_details(i_record_id):
             # end of looping through qualifications
             # end of looping through qualifications
             d_out["uploads"] = list(map(dict_row, db.session.query(tbl_uploads.id, tbl_uploads.si_upload_type, tbl_uploads.v_filename, tbl_uploads.v_description, tbl_qualifications.v_qualification_name).join(tbl_qualifications, tbl_qualifications.id==tbl_uploads.i_matching_id, isouter=True).filter(tbl_uploads.i_record_id==i_record_id).all()))
             d_out["uploads"] = list(map(dict_row, db.session.query(tbl_uploads.id, tbl_uploads.si_upload_type, tbl_uploads.v_filename, tbl_uploads.v_description, tbl_qualifications.v_qualification_name).join(tbl_qualifications, tbl_qualifications.id==tbl_uploads.i_matching_id, isouter=True).filter(tbl_uploads.i_record_id==i_record_id).all()))
             for ix, d in enumerate(d_out["uploads"]): d["si_upload_type"] = {0: "Original CV", 1: "Alteram CV", 2: "Certificate/Diploma/Degree", 3: "I.D. Document or Passport"}[d["si_upload_type"]]
             for ix, d in enumerate(d_out["uploads"]): d["si_upload_type"] = {0: "Original CV", 1: "Alteram CV", 2: "Certificate/Diploma/Degree", 3: "I.D. Document or Passport"}[d["si_upload_type"]]
+            d_out["tenders"] = list(map(dict_row, db.session.query(tbl_tender_cvs.id, tbl_tenders.v_reference_number).join(tbl_tenders, tbl_tenders.id==tbl_tender_cvs.i_tender_id, isouter=False).filter(tbl_tender_cvs.i_record_id==i_record_id).order_by(tbl_tender_cvs.dt_when).limit(3)))
         # end of initial query length check
         # end of initial query length check
         return make_response(jsonify(d_out), 200)
         return make_response(jsonify(d_out), 200)
     except Exception as exc:
     except Exception as exc:
@@ -789,6 +824,100 @@ def css_sample():
 # end of css_sample view function for route /css_sample
 # end of css_sample view function for route /css_sample
 
 
 
 
-s_todo = """
-    double-check both try-except across the board, along with then logging exceptions
-"""
+@bp.route("/tenders/", methods=["GET", "POST"])
+@login_required
+@check_admin
+def tenders():
+    """manage tenders available for assignment to records"""
+    try:
+        tender_form = TenderForm()
+        remove_tender_form = TenderRemovalForm()
+        if tender_form.validate_on_submit() and request.form.get("btn_save_tender", "")=="Save":
+            i_tender_id, s_reference_number, s_description = (int(tender_form.hid_tender_id.data), str(tender_form.txt_reference_number.data), str(tender_form.txt_description.data))
+            if i_tender_id > 0:
+                o_tender = db.session.get(tbl_tenders, i_tender_id)
+                if o_tender is not None:
+                    if db.session.query(tbl_tenders).filter(tbl_tenders.id!=i_tender_id, tbl_tenders.v_reference_number==s_reference_number).count()>0:
+                        flash("There is already another tender with the same reference number on record", "error")
+                    else:
+                        o_tender.v_reference_number = s_reference_number
+                        o_tender.v_description = s_description
+                        db.session.add(o_tender)
+                        db.session.commit()
+                        flash("Tender updated", "success")
+                    # end of making sure no other duplicates with same reference number
+                else:
+                    flash("No tender record could be retrieved", "error")
+                # end of checking if record existed
+            else:
+                if db.session.query(tbl_tenders.id).filter(tbl_tenders.v_reference_number==s_reference_number).count()<1:
+                    db.session.add(tbl_tenders(v_reference_number=s_reference_number, v_description=s_description))
+                    db.session.commit()
+                    flash("Tender inserted", "success")
+                else:
+                    flash("Atender with the same reference number has already been recorded", "error")
+                # end of making sure new tender is not a duplicate
+            # end of checking if new or existing tender record
+        elif remove_tender_form.validate_on_submit():
+            i_tender_id = int(remove_tender_form.hid_remove_tender_id.data)
+            o_tender = db.session.get(tbl_tenders, i_tender_id)
+            if o_tender is not None:
+                db.session.delete(o_tender)
+                db.session.commit()
+                db.session.execute(delete(tbl_tender_cvs).where(tbl_tender_cvs.i_tender_id==i_tender_id))
+                db.session.commit()
+                flash("Tender removed", "success")
+            # end of checking if record existed
+        # end of checking for form submission
+        tender_form.hid_tender_id.data, tender_form.txt_reference_number.data, tender_form.txt_description.data = (0, "", "")
+        remove_tender_form.hid_remove_tender_id.data = "0"
+        i_page = request.form.get("hid_page", 1, type=int)
+        q_tenders = db.session.query(tbl_tenders.id, tbl_tenders.v_reference_number, tbl_tenders.v_description).order_by(tbl_tenders.v_reference_number)
+        pagination = q_tenders.paginate(page=i_page, per_page=20)
+        l_tenders = list(map(dict_row, pagination.items))
+        s_base = "base_bs.html" if Config.BOOTSTRAP else "base.html"
+        s_url = url_for("main.tenders")#, _external=True)
+        return render_template("tenders.html", js=True, base=s_base, url=s_url, tenders=l_tenders, form=tender_form, remove_form=remove_tender_form, paging=pagination)
+    except Exception as exc:
+        return render_template_string(end_user_debugging("tenders"))
+    # end of surrounding try-except
+# end of tenders view function for route /tenders
+
+
+@bp.route("/tenders_list/", methods=["GET"])
+@login_required
+def tenders_list():
+    """return list of tender entries"""
+    try:
+        l_out = []
+        try:
+            q_tenders = db.session.query(tbl_tenders.id, tbl_tenders.v_reference_number, tbl_tenders.v_description)
+            if q_tenders.count()>0:
+                q_tenders = q_tenders.order_by(tbl_tenders.v_reference_number)
+                l_out = list(map(dict_row, q_tenders.all()))
+            # end of checking result count of query
+        except Exception as exc:
+            print(extract_exc("list roles?"))
+        # end of try-except
+        return make_response(jsonify(l_out), 200)
+    except Exception as exc:
+        return render_template_string(end_user_debugging("tenders_list"))
+    # end of surrounding try-except
+# end of tenders_list view function for route /tenders_list/
+
+
+@bp.route("/tender_details/<int:i_tender_id>/", methods=["GET"])
+@login_required
+def tender_details(i_tender_id):
+    """retrieve tender details"""
+    try:
+        d_out = {}
+        o_tender = db.session.get(tbl_tenders, i_tender_id)
+        if o_tender is not None:
+            d_out = dict_instance(o_tender)
+        # end of checking if record retrieved
+        return make_response(jsonify(d_out), 200)
+    except Exception as exc:
+        return render_template_string(end_user_debugging("tender_details"))
+    # end of surrounding try-except
+# end of tender_details view function for route /tender_details/<int:i_tender_id>/

+ 21 - 0
flask_app/app/models/cv_data.py

@@ -128,3 +128,24 @@ class tbl_roles(Base):
 
 
     i_department = relationship('tbl_role_departments')
     i_department = relationship('tbl_role_departments')
 # end of tbl_roles ORM model class
 # end of tbl_roles ORM model class
+
+
+class tbl_tender_cvs(Base):
+    __tablename__ = 'tbl_tender_cvs'
+    __table_args__ = {'schema': 'cv_data'}
+
+    id = db.Column(db.Integer, primary_key=True, server_default=text("nextval('cv_data.tbl_tender_cvs_id_seq'::regclass)"))
+    i_record_id = db.Column(db.Integer, nullable=False, server_default=text("0"))
+    i_tender_id = db.Column(db.Integer, nullable=False, server_default=text("0"))
+    dt_when = db.Column(db.DateTime, nullable=False, server_default=text("CURRENT_TIMESTAMP"))
+# end of tbl_tender_cvs ORM model class
+
+
+class tbl_tenders(Base):
+    __tablename__ = 'tbl_tenders'
+    __table_args__ = {'schema': 'cv_data'}
+
+    id = db.Column(db.Integer, primary_key=True, server_default=text("nextval('cv_data.tbl_tenders_id_seq'::regclass)"))
+    v_reference_number = db.Column(db.String(64), nullable=False, server_default=text("''::character varying"))
+    v_description = db.Column(db.String(512), nullable=False, server_default=text("''::character varying"))
+# end of tbl_tenders ORM model class

+ 1 - 0
flask_app/app/templates/base.html

@@ -71,6 +71,7 @@ if (String(s_msg).length>0) {
 <li><a href="{{ url_for("main.qualifications") }}">Qualifications</a></li>
 <li><a href="{{ url_for("main.qualifications") }}">Qualifications</a></li>
 <li><a href="{{ url_for("main.roles") }}">Positions | Roles</a></li>
 <li><a href="{{ url_for("main.roles") }}">Positions | Roles</a></li>
 <li><a href="{{ url_for("main.users") }}">Access User Profiles</a></li>
 <li><a href="{{ url_for("main.users") }}">Access User Profiles</a></li>
+<li><a href="{{ url_for("main.tenders") }}">Tenders</a></li>
 {% endif %}{# end of checking for bl_admin #}
 {% endif %}{# end of checking for bl_admin #}
 {% if current_user.bl_capture or current_user.bl_admin %}
 {% if current_user.bl_capture or current_user.bl_admin %}
 <li><a href="{{ url_for("main.capture_record") }}">Capture record</a></li>
 <li><a href="{{ url_for("main.capture_record") }}">Capture record</a></li>

+ 32 - 1
flask_app/app/templates/capture_record.html

@@ -8,6 +8,7 @@
 <form action="{{ url_for("main.capture_record", i_record=record_id) }}" method="post" id="frm_capture">
 <form action="{{ url_for("main.capture_record", i_record=record_id) }}" method="post" id="frm_capture">
 {{ form.csrf_token }}
 {{ form.csrf_token }}
 {{ form.hid_record_id }}
 {{ form.hid_record_id }}
+<h3>Basic Details</h3>
 <div class="table-container">
 <div class="table-container">
 <table class="data-table">
 <table class="data-table">
 <tr>
 <tr>
@@ -81,6 +82,7 @@
 <input type="submit" name="btn_save" value="Save">
 <input type="submit" name="btn_save" value="Save">
 </form>
 </form>
 {% if record_id>0 %}
 {% if record_id>0 %}
+<h3>Qualifications</h3>
 <div><a href="#" id="a_add_qualification">Add qualification</a></div>
 <div><a href="#" id="a_add_qualification">Add qualification</a></div>
 {% if record_qualifications %}
 {% if record_qualifications %}
 <ul>
 <ul>
@@ -89,7 +91,22 @@
 {% endfor %}
 {% endfor %}
 </ul>
 </ul>
 {% endif %}{# end of checking for existing qualification records #}
 {% endif %}{# end of checking for existing qualification records #}
-{% endif %}{# end of checking if existing record to then  render qualifications #}
+<h3>Tender Applications</h3>
+<div>
+<form action="{{ url_for("main.capture_record", i_record=record_id) }}" method="post" id="frm_tender">
+{{ tender_form.csrf_token }}
+{{ tender_form.sel_tender.label }}&nbsp;{{ tender_form.sel_tender }}<br>
+<input type="submit" name="btn_allocate" value="Allocate">
+</form>
+</div>
+{% if prior_tenders %}
+<ul>
+{% for tender in prior_tenders %}
+<li><span style="font-weight: bold;">Reference Number:</span>&nbsp;{{ tender.v_reference_number }}&nbsp;{{ tender.dt_when }}&nbsp;<a href="#{{ tender.id }}" class="a_remove_tender">{{ icons.delete_svg(s_label="Remove tender allocation") }}</a><br><blockquote>{{ tender.v_description }}</blockquote></li>
+{% endfor %}{# end of looping through prior_tenders #}
+</ul>
+{% endif %}
+{% endif %}{# end of checking if existing record to then  render qualifications and possibly prior tender associations #}
 </div><!-- end of div.content -->
 </div><!-- end of div.content -->
 {% from "macros/dialog.html" import dlg_prep with context %}
 {% from "macros/dialog.html" import dlg_prep with context %}
 {{ dlg_prep(["dlg_language", "dlg_qualification"]) }}
 {{ dlg_prep(["dlg_language", "dlg_qualification"]) }}
@@ -268,6 +285,16 @@ $(".a_remove_qualification").click( function(event) {
     }// end of confirmation check
     }// end of confirmation check
 });// end of .a_remove_qualification click event
 });// end of .a_remove_qualification click event
 
 
+$(".a_remove_tender").click( function(event) {
+    event.preventDefault();
+    var s_id = String($(this).attr("href")).replace("#", "");
+    var bl_confirm = confirm("Are you sure you wish to remove tender allocation from this C.V.?");
+    if (bl_confirm) {
+        $("#hid_tender_cv_id").val(s_id);
+        document.getElementById("frm_remove_tender").submit();
+    }// end of confirmation check
+});// end of .a_remove_tender click event
+
 } catch(e) {
 } catch(e) {
     var s_err = String(e.name) + "\nmessage:" + String(e.message);
     var s_err = String(e.name) + "\nmessage:" + String(e.message);
     s_err = (typeof(e.lineNumber)!="undefined") ? s_err + "\nline:" + String(e.lineNumber) : s_err;
     s_err = (typeof(e.lineNumber)!="undefined") ? s_err + "\nline:" + String(e.lineNumber) : s_err;
@@ -280,4 +307,8 @@ $(".a_remove_qualification").click( function(event) {
 {{ remove_qualification_form.csrf_token }}
 {{ remove_qualification_form.csrf_token }}
 {{remove_qualification_form.hid_remove_qualification_id }}
 {{remove_qualification_form.hid_remove_qualification_id }}
 </form>
 </form>
+<form action="{{ url_for("main.capture_record", i_record=record_id) }}" method="post" id="frm_remove_tender">
+{{ remove_tender_form.csrf_token }}
+{{ remove_tender_form.hid_tender_cv_id }}
+</form>
 {% endblock %}
 {% endblock %}

+ 22 - 2
flask_app/app/templates/index.html

@@ -156,6 +156,10 @@ font-size: smaller;
 <h4>Uploads</h4>
 <h4>Uploads</h4>
 <ul id="ul_uploads"></ul>
 <ul id="ul_uploads"></ul>
 </div>
 </div>
+<span id="spn_tenders">
+<h4>Prior Tenders</h4>
+<ul id="ul_tenders"></ul>
+</span>
 </div><!-- end of dlg_details -->
 </div><!-- end of dlg_details -->
 <script type="text/javascript">
 <script type="text/javascript">
 $(document).ready( function() {
 $(document).ready( function() {
@@ -258,7 +262,7 @@ try {
                 s_html = s_html + "<li><span class=\"label\">Employment Position/Role:</label>&nbsp;" + String(o_data.record["v_role_name"]) + "</li>\n";
                 s_html = s_html + "<li><span class=\"label\">Employment Position/Role:</label>&nbsp;" + String(o_data.record["v_role_name"]) + "</li>\n";
                 $("#ul_details").append(s_html);
                 $("#ul_details").append(s_html);
             }// end of typeof check against basic details
             }// end of typeof check against basic details
-            // qualifications
+            // languagess
             s_html = "";
             s_html = "";
             if (typeof(o_data.languages)=="object") {
             if (typeof(o_data.languages)=="object") {
             if (o_data.languages.length>0) {
             if (o_data.languages.length>0) {
@@ -271,10 +275,26 @@ try {
                 $("#ul_languages").append(s_html);
                 $("#ul_languages").append(s_html);
             } else {
             } else {
                 $("#spn_languages").hide();
                 $("#spn_languages").hide();
-            }// end of .length check against qualifications
+            }// end of .length check against languages
             } else {
             } else {
                 $("#spn_languages").hide();
                 $("#spn_languages").hide();
             }// end of typeof check against language data
             }// end of typeof check against language data
+            // tenders
+            s_html = "";
+            if (typeof(o_data.tenders)=="object") {
+            if (o_data.tenders.length>0) {
+                $.each(o_data.tenders, function(ix, t) {
+                    s_html = s_html + "<li><span class=\"label\">Reference no.:</span>&nbsp;" + String(t.v_reference_number) + "</li>\n";
+                    s_html = s_html + "</ul>\n";
+                });// end of looping through tenders
+                $("#ul_tenders").append(s_html);
+            } else {
+                $("#spn_tenders").hide();
+            }// end of .length check against languages
+            } else {
+                $("#spn_tenders").hide();
+            }// end of typeof check against prior tender data
+            // qualifications
             if (typeof(o_data.qualifications)=="object") {
             if (typeof(o_data.qualifications)=="object") {
             if (o_data.qualifications.length>0) {
             if (o_data.qualifications.length>0) {
                 $.each(o_data.qualifications, function(ix, q) {
                 $.each(o_data.qualifications, function(ix, q) {

+ 171 - 0
flask_app/app/templates/tenders.html

@@ -0,0 +1,171 @@
+{% extends base %}
+{% block head_extra %}
+<style>
+.label {
+font-weight: bold;
+}
+div.paging {
+color: dark-blue;
+font-size: smaller;
+}
+</style>
+{% endblock %}
+
+{% block content %}
+{% import "macros/action_icons_static.html" as icons %}
+<span class="title"><h2>{% block title %}Tenders{% endblock %}</h2></span>
+<div class="content-container content">
+<div><a href="#" id="a_add_tender" aria-label="Add tender">{{ icons.add_svg }}</a></div>
+{% if tenders %}
+<h3>Tenders</h3>
+<div class="table-container">
+<table class="data-table" id="tbl_tenders">
+<thead>
+<tr>
+<th>Reference Number</th><th>Description</th><th style="font-size: smaller;">[actions]</th>
+</tr>
+</thead>
+{% for tender in tenders %}
+<tr>
+<td>{{ tender.v_reference_number }}</td><td>{{ tender.v_description }}</td>
+<td>
+<a href="#{{ tender.id }}" class="a_edit_tender">{{ icons.edit_svg() }}</a>
+<a href="#{{ tender.id }}" class="a_remove_tender">{{ icons.delete_svg() }}</a>
+</td>
+</tr>
+{% endfor %}{# end of looping through tenders #}
+</table><!-- end of tbl_tenders -->
+</div><!-- end of div.table-container -->
+<div class="paging">
+<div>Paging...</div>
+
+{#
+{% if paging.has_prev %}
+<!-- prev_num --><span><a class="a_page_number" href="#{{ paging.prev_num }}"{{ "<<" }}</a></span>
+{% endif %}
+#}
+
+{% for number in paging.iter_pages() %}
+{% if paging.page != number %}
+<!-- page_num --><span><a class="a_page_number" href="#{{ number }}">{{ number }}</a></span>&nbsp;&nbsp;
+{% else %}
+<!-- current_num --><span class="current-page-number">{{ number }}</span>&nbsp;&nbsp;
+{% endif %}
+{% endfor %}
+
+{#
+{% if paging.has_next %}
+<span>
+<!-- next_num --><a class="a_page_number" href="#{{ paging.next_num }}">{{ ">>" }}</a></span>
+{% endif %}
+#}
+
+</div><!-- end of div.paging -->
+{% endif %}{# end of checking if tenders existed #}
+</div><!-- end of div.content -->
+{% from "macros/dialog.html" import dlg_prep with context %}
+{{ dlg_prep(["dlg_tender"]) }}
+{# dlg divs below #}
+<div id="dlg_tender" aria-labeledby="spn_tender">
+<span id="spn_tender">Tender details</span><br>
+<form action="{{ url_for("main.tenders") }}" method="post" id="frm_tender">
+{{ form.csrf_token }}
+{{ form.hid_tender_id }}
+<ul>
+<li>{{ form.txt_reference_number.label }}&nbsp;{{ form.txt_reference_number }}</li>
+<li>{{ form.txt_description.label }}<br>
+{{ form.txt_description }}</li>
+</ul>
+<input type="submit" name="btn_save_tender" value="Save">
+</form>
+</div><!-- end of dlg_tender -->
+<script type="text/javascript">
+$(document).ready( function() {
+
+try {
+
+var s_dlg_tender = $("#dlg_tender").html();
+
+$("#a_add_tender").click( function(event) {
+    event.preventDefault();
+    $("#dlg_tender").html(s_dlg_tender);
+    $("#dlg_tender").redraw();
+    $("#dlg_tender").dialog("open");
+    $("#txt_reference_number").focus();
+});// end of #a_add_tender click event
+
+$("#tbl_tenders").on("click", ".a_edit_tender", function(event) {
+try {
+    event.preventDefault();
+    $("#dlg_tender").html(s_dlg_tender);
+    $("#dlg_tender").redraw();
+    var s_id = String($(this).attr("href")).replace("#", "");
+    var s_url = "{{ url_for("main.tender_details", i_tender_id=99999) }}".replace("99999", s_id);
+    $.get(s_url, function(o_data) {
+        if (typeof(o_data)=="object") {
+            var s_reference_number = String(o_data.v_reference_number);
+            var s_description = String(o_data.v_description)
+            $("#hid_tender_id").val(s_id);
+            $("#txt_reference_number").val(s_reference_number);
+            $("#txt_description").val(s_description);
+            $("#dlg_tender").redraw();
+            $("#dlg_tender").dialog("open");
+            $("#txt_reference_number").focus();
+        } else {
+            do_alert(String(o_data));
+        }// end of typeof check against o_data
+    });// end of .get
+} catch(e) {
+    var s_err = String(e.name) + "\nmessage:" + String(e.message);
+    s_err = (typeof(e.lineNumber)!="undefined") ? s_err + "\nline:" + String(e.lineNumber) : s_err;
+    alert("Error! " + s_err);
+}//end of catch
+});// end of .a_edit_tender click event inside tbl_tenders
+
+$("#tbl_tenders").on("click", ".a_remove_tender", function(event) {
+try {
+    event.preventDefault();
+    var bl_confirm = confirm("Are you sure?");
+    if (bl_confirm) {
+        var s_id = String($(this).attr("href")).replace("#", "");
+        $("#hid_remove_tender_id").val(s_id);
+        document.getElementById("frm_remove_tender").submit();
+    }// end of confirmation check
+} catch(e) {
+    var s_err = String(e.name) + "\nmessage:" + String(e.message);
+    s_err = (typeof(e.lineNumber)!="undefined") ? s_err + "\nline:" + String(e.lineNumber) : s_err;
+    alert("Error! " + s_err);
+}//end of catch
+});// end of .a_edit_tender click event inside tbl_tenders
+
+function jump_page(i_page) {
+    i_page = (isNaN(i_page)) ? 1 : Number(i_page);
+    $("#hid_page").val(i_page);
+    document.getElementById("frm_paging").submit();
+}// end of jump_page function
+
+$(".a_page_number").click( function(event) {
+    event.preventDefault();
+    var s_page = String($(this).attr("href")).replace("#", "");
+    i_page = (isNaN(s_page)) ? 1 : Number(s_page);
+    jump_page(i_page);
+});// end of .a_page_number function
+
+window.setTimeout( function() {
+    var s_nada = ""; //alert("hello world");
+}, 300);
+var s = "nada"; // do_alert("hello world");
+
+} catch(e) {
+    var s_err = String(e.name) + "\nmessage:" + String(e.message);
+    s_err = (typeof(e.lineNumber)!="undefined") ? s_err + "\nline:" + String(e.lineNumber) : s_err;
+    alert("Error! " + s_err);
+}//end of catch
+
+});// end of secondary document ready
+</script>
+<form action="{{ url_for("main.tenders") }}" method="post" id="frm_remove_tender">
+{{ remove_form.csrf_token }}
+{{ remove_form.hid_remove_tender_id }}
+</form>
+{% endblock %}