request can update financial verification data
This commit is contained in:
parent
f2dbed1ef1
commit
e3631da8ea
@ -0,0 +1,30 @@
|
|||||||
|
"""add request -> task order relationship
|
||||||
|
|
||||||
|
Revision ID: 0845b2f0f401
|
||||||
|
Revises: 875e4b8a05fc
|
||||||
|
Create Date: 2018-08-22 09:58:43.770718
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '0845b2f0f401'
|
||||||
|
down_revision = '875e4b8a05fc'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('requests', sa.Column('task_order_id', sa.Integer(), nullable=True))
|
||||||
|
op.create_foreign_key(None, 'requests', 'task_order', ['task_order_id'], ['id'])
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_constraint(None, 'requests', type_='foreignkey')
|
||||||
|
op.drop_column('requests', 'task_order_id')
|
||||||
|
# ### end Alembic commands ###
|
@ -5,9 +5,11 @@ from sqlalchemy.orm.exc import NoResultFound
|
|||||||
from sqlalchemy.orm.attributes import flag_modified
|
from sqlalchemy.orm.attributes import flag_modified
|
||||||
|
|
||||||
from atst.models.request import Request
|
from atst.models.request import Request
|
||||||
|
from atst.models.task_order import TaskOrder, Source as TaskOrderSource
|
||||||
from atst.models.request_status_event import RequestStatusEvent, RequestStatus
|
from atst.models.request_status_event import RequestStatusEvent, RequestStatus
|
||||||
from atst.domain.workspaces import Workspaces
|
from atst.domain.workspaces import Workspaces
|
||||||
from atst.database import db
|
from atst.database import db
|
||||||
|
from atst.domain.task_orders import TaskOrders
|
||||||
|
|
||||||
from .exceptions import NotFoundError
|
from .exceptions import NotFoundError
|
||||||
|
|
||||||
@ -107,14 +109,20 @@ class Requests(object):
|
|||||||
except NoResultFound:
|
except NoResultFound:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
request = Requests._merge_body(request, request_delta)
|
||||||
|
|
||||||
|
db.session.add(request)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _merge_body(cls, request, request_delta):
|
||||||
request.body = deep_merge(request_delta, request.body)
|
request.body = deep_merge(request_delta, request.body)
|
||||||
|
|
||||||
# Without this, sqlalchemy won't notice the change to request.body,
|
# Without this, sqlalchemy won't notice the change to request.body,
|
||||||
# since it doesn't track dictionary mutations by default.
|
# since it doesn't track dictionary mutations by default.
|
||||||
flag_modified(request, "body")
|
flag_modified(request, "body")
|
||||||
|
|
||||||
db.session.add(request)
|
return request
|
||||||
db.session.commit()
|
|
||||||
|
|
||||||
return request
|
return request
|
||||||
|
|
||||||
@ -215,3 +223,25 @@ WHERE requests_with_status.status = :status
|
|||||||
def completed_count(cls):
|
def completed_count(cls):
|
||||||
return Requests.status_count(RequestStatus.APPROVED)
|
return Requests.status_count(RequestStatus.APPROVED)
|
||||||
|
|
||||||
|
_TASK_ORDER_DATA = [col.name for col in TaskOrder.__table__.c if col.name != "id"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def update_financial_verification(cls, request_id, financial_data):
|
||||||
|
request = Requests.get(request_id)
|
||||||
|
|
||||||
|
request_data = financial_data.copy()
|
||||||
|
task_order_data = {k: request_data.pop(k) for (k,v) in financial_data.items() if k in Requests._TASK_ORDER_DATA}
|
||||||
|
|
||||||
|
task_order = None
|
||||||
|
if task_order_data:
|
||||||
|
task_order_data["number"] = request_data.pop("task_order_number")
|
||||||
|
task_order = TaskOrders.create(**task_order_data, source=TaskOrderSource.MANUAL)
|
||||||
|
else:
|
||||||
|
task_order = TaskOrders.get(financial_data["task_order_number"])
|
||||||
|
|
||||||
|
request.task_order = task_order
|
||||||
|
Requests._merge_body(request, {"financial_verification": request_data})
|
||||||
|
|
||||||
|
db.session.add(task_order)
|
||||||
|
db.session.add(request)
|
||||||
|
db.session.commit()
|
||||||
|
@ -2,7 +2,7 @@ from sqlalchemy.orm.exc import NoResultFound
|
|||||||
from flask import current_app as app
|
from flask import current_app as app
|
||||||
|
|
||||||
from atst.database import db
|
from atst.database import db
|
||||||
from atst.models.task_order import TaskOrder
|
from atst.models.task_order import TaskOrder, Source
|
||||||
from .exceptions import NotFoundError
|
from .exceptions import NotFoundError
|
||||||
|
|
||||||
|
|
||||||
@ -26,13 +26,14 @@ class TaskOrders(object):
|
|||||||
def _get_from_eda(cls, order_number):
|
def _get_from_eda(cls, order_number):
|
||||||
to_data = TaskOrders._client().get_contract(order_number, status="y")
|
to_data = TaskOrders._client().get_contract(order_number, status="y")
|
||||||
if to_data:
|
if to_data:
|
||||||
return TaskOrders.create(to_data["contract_no"])
|
# TODO: we need to determine exactly what we're getting and storing from the EDA client
|
||||||
|
return TaskOrders.create(number=to_data["contract_no"], source=Source.EDA)
|
||||||
else:
|
else:
|
||||||
raise NotFoundError("task_order")
|
raise NotFoundError("task_order")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, order_number):
|
def create(cls, **kwargs):
|
||||||
task_order = TaskOrder(number=order_number)
|
task_order = TaskOrder(**kwargs)
|
||||||
|
|
||||||
db.session.add(task_order)
|
db.session.add(task_order)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
@ -20,6 +20,9 @@ class Request(Base):
|
|||||||
user_id = Column(ForeignKey("users.id"), nullable=False)
|
user_id = Column(ForeignKey("users.id"), nullable=False)
|
||||||
creator = relationship("User")
|
creator = relationship("User")
|
||||||
|
|
||||||
|
task_order_id = Column(ForeignKey("task_order.id"))
|
||||||
|
task_order = relationship("TaskOrder")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def status(self):
|
def status(self):
|
||||||
return self.status_events[-1].new_status
|
return self.status_events[-1].new_status
|
||||||
|
@ -20,7 +20,7 @@ class TaskOrder(Base):
|
|||||||
__tablename__ = "task_order"
|
__tablename__ = "task_order"
|
||||||
|
|
||||||
id = Column(Integer, primary_key=True)
|
id = Column(Integer, primary_key=True)
|
||||||
number = Column(String)
|
number = Column(String, unique=True)
|
||||||
source = Column(SQLAEnum(Source))
|
source = Column(SQLAEnum(Source))
|
||||||
funding_type = Column(SQLAEnum(FundingType))
|
funding_type = Column(SQLAEnum(FundingType))
|
||||||
funding_type_other = Column(String)
|
funding_type_other = Column(String)
|
||||||
|
@ -5,8 +5,9 @@ from atst.domain.exceptions import NotFoundError
|
|||||||
from atst.domain.requests import Requests
|
from atst.domain.requests import Requests
|
||||||
from atst.models.request import Request
|
from atst.models.request import Request
|
||||||
from atst.models.request_status_event import RequestStatus
|
from atst.models.request_status_event import RequestStatus
|
||||||
|
from atst.models.task_order import Source as TaskOrderSource
|
||||||
|
|
||||||
from tests.factories import RequestFactory, UserFactory, RequestStatusEventFactory
|
from tests.factories import RequestFactory, UserFactory, RequestStatusEventFactory, TaskOrderFactory
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
@ -91,3 +92,48 @@ def test_status_count_scoped_to_creator(session):
|
|||||||
|
|
||||||
assert Requests.status_count(RequestStatus.STARTED) == 2
|
assert Requests.status_count(RequestStatus.STARTED) == 2
|
||||||
assert Requests.status_count(RequestStatus.STARTED, creator=user) == 1
|
assert Requests.status_count(RequestStatus.STARTED, creator=user) == 1
|
||||||
|
|
||||||
|
|
||||||
|
request_financial_data = {
|
||||||
|
"pe_id": "123",
|
||||||
|
"task_order_number": "021345",
|
||||||
|
"fname_co": "Contracting",
|
||||||
|
"lname_co": "Officer",
|
||||||
|
"email_co": "jane@mail.mil",
|
||||||
|
"office_co": "WHS",
|
||||||
|
"fname_cor": "Officer",
|
||||||
|
"lname_cor": "Representative",
|
||||||
|
"email_cor": "jane@mail.mil",
|
||||||
|
"office_cor": "WHS",
|
||||||
|
"uii_ids": "1234",
|
||||||
|
"treasury_code": "00123456",
|
||||||
|
"ba_code": "024A",
|
||||||
|
}
|
||||||
|
task_order_financial_data = {
|
||||||
|
"funding_type": "RDTE",
|
||||||
|
"funding_type_other": "other",
|
||||||
|
"clin_0001": 50000,
|
||||||
|
"clin_0003": 13000,
|
||||||
|
"clin_1001": 30000,
|
||||||
|
"clin_1003": 7000,
|
||||||
|
"clin_2001": 30000,
|
||||||
|
"clin_2003": 7000,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# without a matching task order, should create one with status "MANUAL";
|
||||||
|
# with a matching task order, should associate to an existing one
|
||||||
|
def test_update_financial_verification():
|
||||||
|
request1 = RequestFactory.create()
|
||||||
|
financial_data = { **request_financial_data, **task_order_financial_data }
|
||||||
|
Requests.update_financial_verification(request1.id, financial_data)
|
||||||
|
assert request1.task_order
|
||||||
|
assert request1.task_order.clin_0001 == task_order_financial_data["clin_0001"]
|
||||||
|
assert request1.task_order.source == TaskOrderSource.MANUAL
|
||||||
|
|
||||||
|
task_order = TaskOrderFactory.create(source=TaskOrderSource.EDA)
|
||||||
|
new_financial_verification_data = { **request_financial_data, "task_order_number": task_order.number }
|
||||||
|
request2 = RequestFactory.create()
|
||||||
|
Requests.update_financial_verification(request2.id, new_financial_verification_data)
|
||||||
|
assert request2.task_order == task_order
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
from atst.models.task_order import Source as TaskOrderSource
|
||||||
from atst.domain.exceptions import NotFoundError
|
from atst.domain.exceptions import NotFoundError
|
||||||
from atst.domain.task_orders import TaskOrders
|
from atst.domain.task_orders import TaskOrders
|
||||||
from atst.eda_client import MockEDAClient
|
from atst.eda_client import MockEDAClient
|
||||||
@ -19,6 +20,7 @@ def test_can_get_task_order_from_eda(monkeypatch):
|
|||||||
to = TaskOrders.get(MockEDAClient.MOCK_CONTRACT_NUMBER)
|
to = TaskOrders.get(MockEDAClient.MOCK_CONTRACT_NUMBER)
|
||||||
|
|
||||||
assert to.number == MockEDAClient.MOCK_CONTRACT_NUMBER
|
assert to.number == MockEDAClient.MOCK_CONTRACT_NUMBER
|
||||||
|
assert to.source == TaskOrderSource.EDA
|
||||||
|
|
||||||
|
|
||||||
def test_nonexistent_task_order_raises_without_client():
|
def test_nonexistent_task_order_raises_without_client():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user