diff --git a/atst/models/task_order.py b/atst/models/task_order.py index 53afe102..85e4f4ba 100644 --- a/atst/models/task_order.py +++ b/atst/models/task_order.py @@ -57,9 +57,13 @@ class TaskOrder(Base, mixins.TimestampsMixin): self.number, self.budget, self.end_date, self.id ) + @property + def portfolio_name(self): + return self.workspace.name + def to_dictionary(self): return { - "portfolio_name": self.workspace.name, + "portfolio_name": self.portfolio_name, **{ c.name: getattr(self, c.name) for c in self.__table__.columns diff --git a/atst/routes/task_orders/__init__.py b/atst/routes/task_orders/__init__.py index 2de14f43..7d798729 100644 --- a/atst/routes/task_orders/__init__.py +++ b/atst/routes/task_orders/__init__.py @@ -3,3 +3,4 @@ from flask import Blueprint task_orders_bp = Blueprint("task_orders", __name__) from . import new +from . import index diff --git a/atst/routes/task_orders/index.py b/atst/routes/task_orders/index.py new file mode 100644 index 00000000..1146a9ab --- /dev/null +++ b/atst/routes/task_orders/index.py @@ -0,0 +1,17 @@ +from flask import Response + +from . import task_orders_bp +from atst.domain.task_orders import TaskOrders +from atst.utils.docx import Docx + + +@task_orders_bp.route("/task_orders/download_summary/") +def download_summary(task_order_id): + task_order = TaskOrders.get(task_order_id) + byte_str = Docx.render(data=task_order.to_dictionary()) + filename = "{}.docx".format(task_order.portfolio_name) + return Response( + byte_str, + headers={"Content-Disposition": "attachment; filename={}".format(filename)}, + mimetype="application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) diff --git a/atst/utils/docx.py b/atst/utils/docx.py index 86fa04a0..df543948 100644 --- a/atst/utils/docx.py +++ b/atst/utils/docx.py @@ -42,4 +42,4 @@ class Docx: Docx._write(docx_template, docx_file, document) docx_file.close() byte_str.seek(0) - return byte_str.read() + return byte_str diff --git a/tests/factories.py b/tests/factories.py index d2b9e82a..fb2779dd 100644 --- a/tests/factories.py +++ b/tests/factories.py @@ -377,8 +377,8 @@ class TaskOrderFactory(Base): defense_component = factory.LazyFunction(random_service_branch) app_migration = random_choice(data.APP_MIGRATION) native_apps = random.choices(["yes", "no", "not_sure"]) - complexity = random_choice(data.PROJECT_COMPLEXITY) - dev_team = random_choice(data.DEV_TEAM) + complexity = [random_choice(data.PROJECT_COMPLEXITY)] + dev_team = [random_choice(data.DEV_TEAM)] team_experience = random_choice(data.TEAM_EXPERIENCE) scope = factory.Faker("sentence") diff --git a/tests/routes/task_orders/test_index.py b/tests/routes/task_orders/test_index.py new file mode 100644 index 00000000..53b8e9be --- /dev/null +++ b/tests/routes/task_orders/test_index.py @@ -0,0 +1,28 @@ +from flask import url_for +from io import BytesIO +import re +from zipfile import ZipFile + +from atst.utils.docx import Docx + +from tests.factories import TaskOrderFactory + + +def xml_translated(val): + return re.sub("'", "'", str(val)) + + +def test_download_summary(client, user_session): + user_session() + task_order = TaskOrderFactory.create() + response = client.get( + url_for("task_orders.download_summary", task_order_id=task_order.id) + ) + bytes_str = BytesIO(response.data) + zip_ = ZipFile(bytes_str, mode="r") + doc = zip_.read(Docx.DOCUMENT_FILE).decode() + for attr, val in task_order.to_dictionary().items(): + assert attr in doc + if not xml_translated(val) in doc: + __import__("ipdb").set_trace() + assert xml_translated(val) in doc diff --git a/tests/utils/test_docx.py b/tests/utils/test_docx.py index 6d3064e0..e35e2fc4 100644 --- a/tests/utils/test_docx.py +++ b/tests/utils/test_docx.py @@ -7,6 +7,6 @@ from atst.utils.docx import Docx def test_render_docx(): data = {"droid_class": "R2"} docx_file = Docx.render(data=data) - zip_ = ZipFile(BytesIO(docx_file), mode="r") + zip_ = ZipFile(docx_file, mode="r") document = zip_.read(Docx.DOCUMENT_FILE) assert b"droid_class: R2" in document