The BaseDomainClass.get can accept any number of keyword arguments and will add a filter to the query for each kwarg. This will allow the caller to scope the query as needed with kwargs.
189 lines
5.0 KiB
Python
189 lines
5.0 KiB
Python
from flask import current_app as app
|
|
|
|
from atst.database import db
|
|
from atst.models.task_order import TaskOrder
|
|
from atst.models.dd_254 import DD254
|
|
from . import BaseDomainClass
|
|
from atst.domain.portfolios import Portfolios
|
|
from atst.domain.permission_sets import PermissionSets
|
|
|
|
|
|
class TaskOrderError(Exception):
|
|
pass
|
|
|
|
|
|
class TaskOrders(BaseDomainClass):
|
|
model = TaskOrder
|
|
resource_name = "task_order"
|
|
|
|
SECTIONS = {
|
|
"app_info": [
|
|
"portfolio_name",
|
|
"scope",
|
|
"defense_component",
|
|
"app_migration",
|
|
"native_apps",
|
|
"complexity",
|
|
"dev_team",
|
|
"team_experience",
|
|
],
|
|
"funding": [
|
|
"performance_length",
|
|
"csp_estimate",
|
|
"clin_01",
|
|
"clin_02",
|
|
"clin_03",
|
|
"clin_04",
|
|
],
|
|
"oversight": [
|
|
"ko_first_name",
|
|
"ko_last_name",
|
|
"ko_email",
|
|
"ko_phone_number",
|
|
"cor_first_name",
|
|
"cor_last_name",
|
|
"cor_email",
|
|
"cor_phone_number",
|
|
"so_first_name",
|
|
"so_last_name",
|
|
"so_email",
|
|
"so_phone_number",
|
|
],
|
|
}
|
|
|
|
UNCLASSIFIED_FUNDING = ["performance_length", "csp_estimate", "clin_01", "clin_03"]
|
|
|
|
@classmethod
|
|
def create(cls, creator, portfolio):
|
|
task_order = TaskOrder(portfolio=portfolio, creator=creator)
|
|
|
|
db.session.add(task_order)
|
|
db.session.commit()
|
|
|
|
return task_order
|
|
|
|
@classmethod
|
|
def update(cls, task_order, **kwargs):
|
|
for key, value in kwargs.items():
|
|
setattr(task_order, key, value)
|
|
|
|
db.session.add(task_order)
|
|
db.session.commit()
|
|
|
|
return task_order
|
|
|
|
@classmethod
|
|
def section_completion_status(cls, task_order, section):
|
|
if section in TaskOrders.mission_owner_sections():
|
|
passed = []
|
|
failed = []
|
|
|
|
for attr in TaskOrders.SECTIONS[section]:
|
|
if getattr(task_order, attr) is not None:
|
|
passed.append(attr)
|
|
else:
|
|
failed.append(attr)
|
|
|
|
if not failed:
|
|
return "complete"
|
|
elif passed and failed:
|
|
return "draft"
|
|
|
|
return "incomplete"
|
|
|
|
@classmethod
|
|
def all_sections_complete(cls, task_order):
|
|
for section in TaskOrders.SECTIONS.keys():
|
|
if (
|
|
TaskOrders.section_completion_status(task_order, section)
|
|
is not "complete"
|
|
):
|
|
return False
|
|
|
|
return True
|
|
|
|
@classmethod
|
|
def can_ko_sign(cls, task_order):
|
|
return (
|
|
TaskOrders.all_sections_complete(task_order)
|
|
and DD254s.is_complete(task_order.dd_254)
|
|
and not TaskOrders.is_signed_by_ko(task_order)
|
|
)
|
|
|
|
@classmethod
|
|
def is_signed_by_ko(cls, task_order):
|
|
return task_order.signer_dod_id is not None
|
|
|
|
@classmethod
|
|
def mission_owner_sections(cls):
|
|
section_list = TaskOrders.SECTIONS
|
|
if not app.config.get("CLASSIFIED"):
|
|
section_list["funding"] = TaskOrders.UNCLASSIFIED_FUNDING
|
|
return section_list
|
|
|
|
OFFICERS = [
|
|
"contracting_officer",
|
|
"contracting_officer_representative",
|
|
"security_officer",
|
|
]
|
|
|
|
@classmethod
|
|
def add_officer(cls, task_order, officer_type, officer_data):
|
|
if officer_type in TaskOrders.OFFICERS:
|
|
portfolio = task_order.portfolio
|
|
|
|
existing_member = next(
|
|
(
|
|
member
|
|
for member in portfolio.members
|
|
if member.user.dod_id == officer_data["dod_id"]
|
|
),
|
|
None,
|
|
)
|
|
|
|
if existing_member:
|
|
portfolio_user = existing_member.user
|
|
else:
|
|
member = Portfolios.create_member(
|
|
portfolio,
|
|
{
|
|
**officer_data,
|
|
"permission_sets": [PermissionSets.EDIT_PORTFOLIO_FUNDING],
|
|
},
|
|
)
|
|
portfolio_user = member.user
|
|
|
|
setattr(task_order, officer_type, portfolio_user)
|
|
|
|
db.session.add(task_order)
|
|
db.session.commit()
|
|
|
|
return portfolio_user
|
|
else:
|
|
raise TaskOrderError(
|
|
"{} is not an officer role on task orders".format(officer_type)
|
|
)
|
|
|
|
@classmethod
|
|
def add_dd_254(user, task_order, dd_254_data):
|
|
dd_254 = DD254(**dd_254_data)
|
|
task_order.dd_254 = dd_254
|
|
|
|
db.session.add(task_order)
|
|
db.session.commit()
|
|
|
|
|
|
class DD254s:
|
|
# TODO: standin implementation until we have a real download,
|
|
# sign, and verify process for the DD 254 PDF
|
|
@classmethod
|
|
def is_complete(cls, dd254):
|
|
if dd254 is None:
|
|
return False
|
|
|
|
for col in DD254.__table__.columns:
|
|
if getattr(dd254, col.name) is None:
|
|
return False
|
|
|
|
return True
|