Merge pull request #615 from dod-ccpo/signature
Add in basic implementation of the KO TO signature page
This commit is contained in:
@@ -222,3 +222,28 @@ class OversightForm(CacheableForm):
|
||||
|
||||
class ReviewForm(CacheableForm):
|
||||
pass
|
||||
|
||||
|
||||
class SignatureForm(CacheableForm):
|
||||
level_of_warrant = DecimalField(
|
||||
translate("task_orders.sign.level_of_warrant_label"),
|
||||
description=translate("task_orders.sign.level_of_warrant_description"),
|
||||
validators=[
|
||||
RequiredIf(
|
||||
lambda form: (
|
||||
form._fields.get("unlimited_level_of_warrant").data is not True
|
||||
)
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
unlimited_level_of_warrant = BooleanField(
|
||||
translate("task_orders.sign.unlimited_level_of_warrant_description"),
|
||||
validators=[Optional()],
|
||||
)
|
||||
|
||||
signature = BooleanField(
|
||||
translate("task_orders.sign.digital_signature_label"),
|
||||
description=translate("task_orders.sign.digital_signature_description"),
|
||||
validators=[Required()],
|
||||
)
|
||||
|
@@ -2,7 +2,16 @@ from enum import Enum
|
||||
from datetime import date
|
||||
|
||||
import pendulum
|
||||
from sqlalchemy import Boolean, Column, Numeric, String, ForeignKey, Date, Integer
|
||||
from sqlalchemy import (
|
||||
Column,
|
||||
Numeric,
|
||||
String,
|
||||
ForeignKey,
|
||||
Date,
|
||||
Integer,
|
||||
DateTime,
|
||||
Boolean,
|
||||
)
|
||||
from sqlalchemy.ext.hybrid import hybrid_property
|
||||
from sqlalchemy.types import ARRAY
|
||||
from sqlalchemy.orm import relationship
|
||||
@@ -80,6 +89,10 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
||||
number = Column(String, unique=True) # Task Order Number
|
||||
loa = Column(String) # Line of Accounting (LOA)
|
||||
custom_clauses = Column(String) # Custom Clauses
|
||||
signer_dod_id = Column(String)
|
||||
signed_at = Column(DateTime)
|
||||
level_of_warrant = Column(Numeric(scale=2))
|
||||
unlimited_level_of_warrant = Column(Boolean)
|
||||
|
||||
@hybrid_property
|
||||
def csp_estimate(self):
|
||||
|
@@ -92,11 +92,7 @@ def submit_ko_review(portfolio_id, task_order_id, form=None):
|
||||
if form.validate():
|
||||
TaskOrders.update(user=g.current_user, task_order=task_order, **form.data)
|
||||
return redirect(
|
||||
url_for(
|
||||
"portfolios.view_task_order",
|
||||
portfolio_id=portfolio_id,
|
||||
task_order_id=task_order_id,
|
||||
)
|
||||
url_for("task_orders.signature_requested", task_order_id=task_order_id)
|
||||
)
|
||||
else:
|
||||
return render_template(
|
||||
|
@@ -5,3 +5,4 @@ task_orders_bp = Blueprint("task_orders", __name__)
|
||||
from . import new
|
||||
from . import index
|
||||
from . import invite
|
||||
from . import signing
|
||||
|
74
atst/routes/task_orders/signing.py
Normal file
74
atst/routes/task_orders/signing.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from flask import url_for, redirect, render_template, g, request as http_request
|
||||
|
||||
import datetime
|
||||
|
||||
from . import task_orders_bp
|
||||
from atst.domain.authz import Authorization
|
||||
from atst.domain.exceptions import NotFoundError
|
||||
from atst.domain.task_orders import TaskOrders
|
||||
from atst.forms.task_order import SignatureForm
|
||||
from atst.utils.flash import formatted_flash as flash
|
||||
|
||||
|
||||
def find_unsigned_ko_to(task_order_id):
|
||||
task_order = TaskOrders.get(g.current_user, task_order_id)
|
||||
Authorization.check_is_ko(g.current_user, task_order)
|
||||
|
||||
if task_order.signer_dod_id is not None:
|
||||
raise NotFoundError("task_order")
|
||||
|
||||
return task_order
|
||||
|
||||
|
||||
@task_orders_bp.route("/task_orders/<task_order_id>/digital_signature", methods=["GET"])
|
||||
def signature_requested(task_order_id):
|
||||
task_order = find_unsigned_ko_to(task_order_id)
|
||||
|
||||
return render_template(
|
||||
"task_orders/signing/signature_requested.html",
|
||||
task_order_id=task_order.id,
|
||||
form=SignatureForm(),
|
||||
)
|
||||
|
||||
|
||||
@task_orders_bp.route(
|
||||
"/task_orders/<task_order_id>/digital_signature", methods=["POST"]
|
||||
)
|
||||
def record_signature(task_order_id):
|
||||
task_order = find_unsigned_ko_to(task_order_id)
|
||||
|
||||
form_data = {**http_request.form}
|
||||
|
||||
if "unlimited_level_of_warrant" in form_data and form_data[
|
||||
"unlimited_level_of_warrant"
|
||||
] == ["y"]:
|
||||
del form_data["level_of_warrant"]
|
||||
|
||||
form = SignatureForm(form_data)
|
||||
|
||||
if form.validate():
|
||||
TaskOrders.update(
|
||||
user=g.current_user,
|
||||
task_order=task_order,
|
||||
signer_dod_id=g.current_user.dod_id,
|
||||
signed_at=datetime.datetime.now(),
|
||||
**form.data,
|
||||
)
|
||||
|
||||
flash("task_order_signed")
|
||||
return redirect(
|
||||
url_for(
|
||||
"portfolios.view_task_order",
|
||||
portfolio_id=task_order.portfolio_id,
|
||||
task_order_id=task_order.id,
|
||||
)
|
||||
)
|
||||
else:
|
||||
return (
|
||||
render_template(
|
||||
"task_orders/signing/signature_requested.html",
|
||||
task_order_id=task_order_id,
|
||||
form=form,
|
||||
),
|
||||
400,
|
||||
)
|
@@ -1,6 +1,13 @@
|
||||
from flask import flash, render_template_string
|
||||
|
||||
MESSAGES = {
|
||||
"task_order_signed": {
|
||||
"title_template": "Task Order Signed",
|
||||
"message_template": """
|
||||
<p>Task order has been signed successfully</p>
|
||||
""",
|
||||
"category": "success",
|
||||
},
|
||||
"new_portfolio_member": {
|
||||
"title_template": "Member added successfully",
|
||||
"message_template": """
|
||||
|
Reference in New Issue
Block a user