Invite Officer From Manage Invitations Page
This commit is contained in:
parent
39aa160bb6
commit
17c175b698
@ -0,0 +1,27 @@
|
|||||||
|
"""Default Boolean fields to False
|
||||||
|
|
||||||
|
Revision ID: 6512aa8d4641
|
||||||
|
Revises: ec1ba2363191
|
||||||
|
Create Date: 2019-02-27 13:22:03.863516
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '6512aa8d4641'
|
||||||
|
down_revision = 'ec1ba2363191'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.alter_column('task_orders', 'ko_invite', type_=sa.Boolean(), server_default=False)
|
||||||
|
op.alter_column('task_orders', 'so_invite', type_=sa.Boolean(), server_default=False)
|
||||||
|
op.alter_column('task_orders', 'cor_invite', type_=sa.Boolean(), server_default=False)
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.alter_column('task_orders', 'ko_invite', server_default=sa.Boolean())
|
||||||
|
op.alter_column('task_orders', 'so_invite', server_default=sa.Boolean())
|
||||||
|
op.alter_column('task_orders', 'cor_invite', server_default=sa.Boolean())
|
@ -35,6 +35,7 @@ class EditTaskOrderOfficersForm(CacheableForm):
|
|||||||
"email",
|
"email",
|
||||||
"phone_number",
|
"phone_number",
|
||||||
"dod_id",
|
"dod_id",
|
||||||
|
"invite",
|
||||||
]
|
]
|
||||||
|
|
||||||
def process(self, formdata=None, obj=None, data=None, **kwargs):
|
def process(self, formdata=None, obj=None, data=None, **kwargs):
|
||||||
|
@ -74,19 +74,19 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
|||||||
ko_email = Column(String) # Email
|
ko_email = Column(String) # Email
|
||||||
ko_phone_number = Column(String) # Phone Number
|
ko_phone_number = Column(String) # Phone Number
|
||||||
ko_dod_id = Column(String) # DOD ID
|
ko_dod_id = Column(String) # DOD ID
|
||||||
ko_invite = Column(Boolean)
|
ko_invite = Column(Boolean, default=False)
|
||||||
cor_first_name = Column(String) # First Name
|
cor_first_name = Column(String) # First Name
|
||||||
cor_last_name = Column(String) # Last Name
|
cor_last_name = Column(String) # Last Name
|
||||||
cor_email = Column(String) # Email
|
cor_email = Column(String) # Email
|
||||||
cor_phone_number = Column(String) # Phone Number
|
cor_phone_number = Column(String) # Phone Number
|
||||||
cor_dod_id = Column(String) # DOD ID
|
cor_dod_id = Column(String) # DOD ID
|
||||||
cor_invite = Column(Boolean)
|
cor_invite = Column(Boolean, default=False)
|
||||||
so_first_name = Column(String) # First Name
|
so_first_name = Column(String) # First Name
|
||||||
so_last_name = Column(String) # Last Name
|
so_last_name = Column(String) # Last Name
|
||||||
so_email = Column(String) # Email
|
so_email = Column(String) # Email
|
||||||
so_phone_number = Column(String) # Phone Number
|
so_phone_number = Column(String) # Phone Number
|
||||||
so_dod_id = Column(String) # DOD ID
|
so_dod_id = Column(String) # DOD ID
|
||||||
so_invite = Column(Boolean)
|
so_invite = Column(Boolean, default=False)
|
||||||
pdf_attachment_id = Column(ForeignKey("attachments.id"))
|
pdf_attachment_id = Column(ForeignKey("attachments.id"))
|
||||||
_pdf = relationship("Attachment", foreign_keys=[pdf_attachment_id])
|
_pdf = relationship("Attachment", foreign_keys=[pdf_attachment_id])
|
||||||
number = Column(String, unique=True) # Task Order Number
|
number = Column(String, unique=True) # Task Order Number
|
||||||
@ -95,7 +95,7 @@ class TaskOrder(Base, mixins.TimestampsMixin):
|
|||||||
signer_dod_id = Column(String)
|
signer_dod_id = Column(String)
|
||||||
signed_at = Column(DateTime)
|
signed_at = Column(DateTime)
|
||||||
level_of_warrant = Column(Numeric(scale=2))
|
level_of_warrant = Column(Numeric(scale=2))
|
||||||
unlimited_level_of_warrant = Column(Boolean)
|
unlimited_level_of_warrant = Column(Boolean, default=False)
|
||||||
|
|
||||||
@hybrid_property
|
@hybrid_property
|
||||||
def csp_estimate(self):
|
def csp_estimate(self):
|
||||||
|
@ -12,6 +12,7 @@ from atst.forms.officers import EditTaskOrderOfficersForm
|
|||||||
from atst.models.task_order import Status as TaskOrderStatus
|
from atst.models.task_order import Status as TaskOrderStatus
|
||||||
from atst.forms.ko_review import KOReviewForm
|
from atst.forms.ko_review import KOReviewForm
|
||||||
from atst.forms.dd_254 import DD254Form
|
from atst.forms.dd_254 import DD254Form
|
||||||
|
from atst.services.invitation import update_officer_invitations
|
||||||
|
|
||||||
|
|
||||||
@portfolios_bp.route("/portfolios/<portfolio_id>/task_orders")
|
@portfolios_bp.route("/portfolios/<portfolio_id>/task_orders")
|
||||||
@ -157,6 +158,7 @@ def edit_task_order_invitations(portfolio_id, task_order_id):
|
|||||||
form.populate_obj(task_order)
|
form.populate_obj(task_order)
|
||||||
db.session.add(task_order)
|
db.session.add(task_order)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
update_officer_invitations(g.current_user, task_order)
|
||||||
|
|
||||||
return redirect(
|
return redirect(
|
||||||
url_for(
|
url_for(
|
||||||
|
@ -3,49 +3,7 @@ from flask import redirect, url_for, g
|
|||||||
from . import task_orders_bp
|
from . import task_orders_bp
|
||||||
from atst.domain.task_orders import TaskOrders
|
from atst.domain.task_orders import TaskOrders
|
||||||
from atst.utils.flash import formatted_flash as flash
|
from atst.utils.flash import formatted_flash as flash
|
||||||
from atst.domain.portfolio_roles import PortfolioRoles
|
from atst.services.invitation import update_officer_invitations
|
||||||
from atst.services.invitation import Invitation as InvitationService
|
|
||||||
|
|
||||||
|
|
||||||
OFFICER_INVITATIONS = [
|
|
||||||
{
|
|
||||||
"field": "ko_invite",
|
|
||||||
"role": "contracting_officer",
|
|
||||||
"subject": "Review a task order",
|
|
||||||
"template": "emails/invitation.txt",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"field": "cor_invite",
|
|
||||||
"role": "contracting_officer_representative",
|
|
||||||
"subject": "Help with a task order",
|
|
||||||
"template": "emails/invitation.txt",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"field": "so_invite",
|
|
||||||
"role": "security_officer",
|
|
||||||
"subject": "Review security for a task order",
|
|
||||||
"template": "emails/invitation.txt",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def update_officer_invitations(user, task_order):
|
|
||||||
for officer_type in OFFICER_INVITATIONS:
|
|
||||||
field = officer_type["field"]
|
|
||||||
if getattr(task_order, field) and not getattr(task_order, officer_type["role"]):
|
|
||||||
officer_data = task_order.officer_dictionary(officer_type["role"])
|
|
||||||
officer = TaskOrders.add_officer(
|
|
||||||
user, task_order, officer_type["role"], officer_data
|
|
||||||
)
|
|
||||||
pf_officer_member = PortfolioRoles.get(task_order.portfolio.id, officer.id)
|
|
||||||
invite_service = InvitationService(
|
|
||||||
user,
|
|
||||||
pf_officer_member,
|
|
||||||
officer_data["email"],
|
|
||||||
subject=officer_type["subject"],
|
|
||||||
email_template=officer_type["template"],
|
|
||||||
)
|
|
||||||
invite_service.invite()
|
|
||||||
|
|
||||||
|
|
||||||
@task_orders_bp.route("/task_orders/invite/<task_order_id>", methods=["POST"])
|
@task_orders_bp.route("/task_orders/invite/<task_order_id>", methods=["POST"])
|
||||||
|
@ -2,6 +2,48 @@ from flask import render_template
|
|||||||
|
|
||||||
from atst.domain.invitations import Invitations
|
from atst.domain.invitations import Invitations
|
||||||
from atst.queue import queue
|
from atst.queue import queue
|
||||||
|
from atst.domain.task_orders import TaskOrders
|
||||||
|
from atst.domain.portfolio_roles import PortfolioRoles
|
||||||
|
|
||||||
|
OFFICER_INVITATIONS = [
|
||||||
|
{
|
||||||
|
"field": "ko_invite",
|
||||||
|
"role": "contracting_officer",
|
||||||
|
"subject": "Review a task order",
|
||||||
|
"template": "emails/invitation.txt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "cor_invite",
|
||||||
|
"role": "contracting_officer_representative",
|
||||||
|
"subject": "Help with a task order",
|
||||||
|
"template": "emails/invitation.txt",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"field": "so_invite",
|
||||||
|
"role": "security_officer",
|
||||||
|
"subject": "Review security for a task order",
|
||||||
|
"template": "emails/invitation.txt",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def update_officer_invitations(user, task_order):
|
||||||
|
for officer_type in OFFICER_INVITATIONS:
|
||||||
|
field = officer_type["field"]
|
||||||
|
if getattr(task_order, field) and not getattr(task_order, officer_type["role"]):
|
||||||
|
officer_data = task_order.officer_dictionary(officer_type["role"])
|
||||||
|
officer = TaskOrders.add_officer(
|
||||||
|
user, task_order, officer_type["role"], officer_data
|
||||||
|
)
|
||||||
|
pf_officer_member = PortfolioRoles.get(task_order.portfolio.id, officer.id)
|
||||||
|
invite_service = Invitation(
|
||||||
|
user,
|
||||||
|
pf_officer_member,
|
||||||
|
officer_data["email"],
|
||||||
|
subject=officer_type["subject"],
|
||||||
|
email_template=officer_type["template"],
|
||||||
|
)
|
||||||
|
invite_service.invite()
|
||||||
|
|
||||||
|
|
||||||
class Invitation:
|
class Invitation:
|
||||||
|
@ -6,6 +6,7 @@ from atst.domain.roles import Roles
|
|||||||
from atst.domain.task_orders import TaskOrders
|
from atst.domain.task_orders import TaskOrders
|
||||||
from atst.models.portfolio_role import Status as PortfolioStatus
|
from atst.models.portfolio_role import Status as PortfolioStatus
|
||||||
from atst.utils.localization import translate
|
from atst.utils.localization import translate
|
||||||
|
from atst.queue import queue
|
||||||
|
|
||||||
from tests.factories import (
|
from tests.factories import (
|
||||||
PortfolioFactory,
|
PortfolioFactory,
|
||||||
@ -136,6 +137,7 @@ class TestTaskOrderInvitations:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_editing_with_partial_data(self, user_session, client):
|
def test_editing_with_partial_data(self, user_session, client):
|
||||||
|
queue_length = len(queue.get_queue())
|
||||||
user_session(self.portfolio.owner)
|
user_session(self.portfolio.owner)
|
||||||
response = self._post(
|
response = self._post(
|
||||||
client,
|
client,
|
||||||
@ -151,8 +153,34 @@ class TestTaskOrderInvitations:
|
|||||||
assert updated_task_order.ko_last_name == "Skywalker"
|
assert updated_task_order.ko_last_name == "Skywalker"
|
||||||
assert updated_task_order.so_first_name == "Boba"
|
assert updated_task_order.so_first_name == "Boba"
|
||||||
assert updated_task_order.so_last_name == "Fett"
|
assert updated_task_order.so_last_name == "Fett"
|
||||||
|
assert len(queue.get_queue()) == queue_length
|
||||||
|
|
||||||
|
def test_editing_with_complete_data(self, user_session, client):
|
||||||
|
queue_length = len(queue.get_queue())
|
||||||
|
|
||||||
|
user_session(self.portfolio.owner)
|
||||||
|
response = self._post(
|
||||||
|
client,
|
||||||
|
{
|
||||||
|
"contracting_officer-first_name": "Luke",
|
||||||
|
"contracting_officer-last_name": "Skywalker",
|
||||||
|
"contracting_officer-dod_id": "0123456789",
|
||||||
|
"contracting_officer-email": "luke@skywalker.mil",
|
||||||
|
"contracting_officer-phone_number": "0123456789",
|
||||||
|
"contracting_officer-invite": "y",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
updated_task_order = TaskOrders.get(self.portfolio.owner, self.task_order.id)
|
||||||
|
|
||||||
|
assert updated_task_order.ko_invite == True
|
||||||
|
assert updated_task_order.ko_first_name == "Luke"
|
||||||
|
assert updated_task_order.ko_last_name == "Skywalker"
|
||||||
|
assert updated_task_order.ko_email == "luke@skywalker.mil"
|
||||||
|
assert updated_task_order.ko_phone_number == "0123456789"
|
||||||
|
assert len(queue.get_queue()) == queue_length + 1
|
||||||
|
|
||||||
def test_editing_with_invalid_data(self, user_session, client):
|
def test_editing_with_invalid_data(self, user_session, client):
|
||||||
|
queue_length = len(queue.get_queue())
|
||||||
user_session(self.portfolio.owner)
|
user_session(self.portfolio.owner)
|
||||||
response = self._post(
|
response = self._post(
|
||||||
client,
|
client,
|
||||||
@ -167,6 +195,7 @@ class TestTaskOrderInvitations:
|
|||||||
|
|
||||||
updated_task_order = TaskOrders.get(self.portfolio.owner, self.task_order.id)
|
updated_task_order = TaskOrders.get(self.portfolio.owner, self.task_order.id)
|
||||||
assert updated_task_order.so_first_name != "Boba"
|
assert updated_task_order.so_first_name != "Boba"
|
||||||
|
assert len(queue.get_queue()) == queue_length
|
||||||
|
|
||||||
|
|
||||||
def test_ko_can_view_task_order(client, user_session):
|
def test_ko_can_view_task_order(client, user_session):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user