From e2bd6bd823d564f6901eff9e332a211109a7419c Mon Sep 17 00:00:00 2001 From: graham-dds Date: Tue, 3 Sep 2019 12:18:38 -0400 Subject: [PATCH 1/2] Reorganize task order review template - update copy in translations - Move TO totals out of sidebar - Group CLINs into 1 table with altered columns, instead of a separate table for each - edit CSS on CLIN table --- atst/models/clin.py | 4 +++ styles/sections/_task_order.scss | 20 +++-------- templates/components/totals_box.html | 6 ++-- templates/fragments/task_order_review.html | 41 +++++++++++----------- translations.yaml | 32 +++++++++-------- 5 files changed, 48 insertions(+), 55 deletions(-) diff --git a/atst/models/clin.py b/atst/models/clin.py index 2f5c3f1c..ba64405e 100644 --- a/atst/models/clin.py +++ b/atst/models/clin.py @@ -35,6 +35,10 @@ class CLIN(Base, mixins.TimestampsMixin): JEDICLINType.JEDI_CLIN_3, ] + @property + def type(self): + return "Base" if self.number[0] == "0" else "Option" + @property def is_completed(self): return all( diff --git a/styles/sections/_task_order.scss b/styles/sections/_task_order.scss index d874abd6..94d71d68 100644 --- a/styles/sections/_task_order.scss +++ b/styles/sections/_task_order.scss @@ -24,29 +24,21 @@ margin-top: $gap * 4; width: 900px; + &__amount { + text-align: right; + } + hr { border: 0; - border-bottom: 1px solid $color-gray-lighter; margin-top: $gap * 4; margin-bottom: $gap * 4; } table { margin-top: 1rem; - table-layout: fixed; th { white-space: nowrap; - word-wrap: normal; - padding: 0.8rem; - - &.task-order__clin-amount { - width: 25%; - } - } - - td { - padding: 0.8rem; } } @@ -73,12 +65,8 @@ } .totals-box { - padding: $gap * 4; - padding-top: $gap * 2; flex-grow: unset; - margin-left: $gap * 6; display: table; - background-color: $color-gray-lightest; min-width: 350px; } } diff --git a/templates/components/totals_box.html b/templates/components/totals_box.html index 5ad39166..cb354fb8 100644 --- a/templates/components/totals_box.html +++ b/templates/components/totals_box.html @@ -9,9 +9,9 @@
{{ 'components.totals_box.obligated_funds' | translate }}
{{ obligated_funds | dollars }}

{{ 'components.totals_box.obligated_text' | translate }}

- -
- + +
+
{{ 'components.totals_box.total_amount' | translate }}
{{ contract_amount | dollars }}

{{ 'components.totals_box.total_text' | translate }}

diff --git a/templates/fragments/task_order_review.html b/templates/fragments/task_order_review.html index 9b938106..80029eb8 100644 --- a/templates/fragments/task_order_review.html +++ b/templates/fragments/task_order_review.html @@ -7,7 +7,10 @@
- {{ "task_orders.review.review_your_task_order" | translate }} + {{ "task_orders.review.review_your_funding" | translate }} +
+
+ {{ TotalsBox(task_order=task_order) }}
@@ -32,40 +35,36 @@ {{ "task_orders.review.funding_summary" | translate }}
- {% for clin in task_order.clins %} -
- {{ "{}".format(clin.jedi_clin_type) | translate}} -
+ - - - - + + + + + + + {% for clin in task_order.clins %} - + + + - - + {# TODO: Swap in total CLIN amount #} + + + {% endfor %}
{{ "task_orders.review.clins.amount" | translate }}{{ "task_orders.review.clins.obligated" | translate }}{{ "task_orders.review.clins.pop_start" | translate }}{{ "task_orders.review.clins.pop_end" | translate }}{{ "task_orders.review.clins.number" | translate }}{{ "task_orders.review.clins.type" | translate }}{{ "task_orders.review.clins.idiq_clin_description" | translate }}{{ "task_orders.review.clins.pop" | translate }}{{ "task_orders.review.clins.amount" | translate }}{{ "task_orders.review.clins.obligated" | translate }}
{{ clin.obligated_amount | dollars }}{{ clin.number }}{{ clin.type }}{{ "{}".format(clin.jedi_clin_type) | translate}} - {% if clin.is_obligated() %} - {{ "common.yes" | translate }} - {% else %} - {{ "common.no" | translate }} - {% endif %} + {{ clin.start_date | formattedDate }} - {{ clin.end_date | formattedDate }} {{ clin.start_date | formattedDate }}{{ clin.end_date | formattedDate }}$123,456,789.00{{ clin.obligated_amount | dollars }}
- {% endfor %}
-
- {{ TotalsBox(task_order=task_order) }} -
diff --git a/translations.yaml b/translations.yaml index a6b8debe..8a530149 100644 --- a/translations.yaml +++ b/translations.yaml @@ -73,10 +73,10 @@ components: destructive_message: You will no longer be able to access this {resource} destructive_title: Warning! This action is permanent totals_box: - obligated_funds: Funds obligated for cloud - obligated_text: This is the funding allocated to cloud services. It may be 100% or a portion of the total task order budget. - total_amount: Total contract amount - total_text: This is the value of all funds obligated for this contract, including -- but not limited to -- funds obligated for the cloud. + obligated_funds: Total Obligated Funds + obligated_text: This amount strictly calculates Base CLINs, and may represent 100% of your total task order budget, or just a portion if you also have Optional Base or Optional CLINs. + total_amount: Total Possible Task Order Funds + total_text: This amount represents the total value of all Base and Option CLINs, including any extensions listed within your task order. usa_header: flag_image_alt: U.S. Flag official_message: An official website of the United States government @@ -350,17 +350,19 @@ portfolios: task_orders: review: pdf_title: Approved Task Order - review_your_task_order: Review your task order - funding_summary: Task Order Summary + review_your_funding: Review your funding + funding_summary: CLIN Summary task_order_number: Task Order Number check_paragraph: Check to make sure the information you entered is correct. After submission, you will confirm this task order was signed by a contracting officer. Thereafter, you will be informed as soon as CCPO completes their review. supporting_document: title: Supporting document clins: - amount: Amount - obligated: Obligated - pop_start: PoP Start - pop_end: PoP End + number: TO CLIN + type: CLIN Type + idiq_clin_description: Description (IDIQ CLIN) + pop: PoP + amount: CLIN Value + obligated: Amount Obligated form: add_clin: Enter another CLIN add_to_header: Add your task order @@ -386,7 +388,7 @@ task_orders: description: Finally, plase confirm that your uploaded document representing the information you've entered contains the required signature from your Contracting Officer. You will be informed as soon as CCPO completes their review. alert_message: All task orders require a Contracting Officer signature. next_button: 'Confirm & Submit' - sticky_header_text: 'Add Funding ({step} of 5)' + sticky_header_text: 'Add Task Order (step {step} of 5)' new: form_help_text: Before you can begin work in the cloud, you'll need to complete the information below and upload your approved task order for reference by the CCPO. app_info: @@ -396,10 +398,10 @@ task_orders: sign: digital_signature_description: I acknowledge that the uploaded task order contains the required KO signature. JEDICLINType: - JEDI_CLIN_1: 'Base CLIN 0001: Unclassified IaaS and PaaS' - JEDI_CLIN_2: 'CLIN 2: Classified Cloud Services - 0002' - JEDI_CLIN_3: 'CLIN 3:' - JEDI_CLIN_4: 'CLIN 4:' + JEDI_CLIN_1: 'Unclassified IaaS and PaaS (IDIQ CLIN 0001)' + JEDI_CLIN_2: 'Classified IaaS and PaaS (IDIQ CLIN 0002)' + JEDI_CLIN_3: 'Unclassified Cloud Support Package (IDIQ CLIN 0003)' + JEDI_CLIN_4: 'Classified Cloud Support Package (IDIQ CLIN 0004)' testing: example_string: Hello World example_with_variables: 'Hello, {name}!' From 41bbbe8a393e438e29ee9da7005b025d60b72d1b Mon Sep 17 00:00:00 2001 From: graham-dds Date: Tue, 3 Sep 2019 11:10:12 -0400 Subject: [PATCH 2/2] add a sorted_clins property for clin sorting logic CLINS have a special ordering: - First, they are sorted by the last three digits - Then, they are sorted by the first digit Trying to add CLIN sorting logic to the relationship field in the task order proved to be more challenging than expected. So, a separate property was defined in order to access the clins in sorted order. --- atst/models/clin.py | 2 +- atst/models/task_order.py | 4 ++++ templates/fragments/task_order_review.html | 2 +- tests/models/test_task_order.py | 19 +++++++++++++++++++ 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/atst/models/clin.py b/atst/models/clin.py index ba64405e..da2d1d02 100644 --- a/atst/models/clin.py +++ b/atst/models/clin.py @@ -38,7 +38,7 @@ class CLIN(Base, mixins.TimestampsMixin): @property def type(self): return "Base" if self.number[0] == "0" else "Option" - + @property def is_completed(self): return all( diff --git a/atst/models/task_order.py b/atst/models/task_order.py index 8d2f03fc..bd592bea 100644 --- a/atst/models/task_order.py +++ b/atst/models/task_order.py @@ -47,6 +47,10 @@ class TaskOrder(Base, mixins.TimestampsMixin): "CLIN", back_populates="task_order", cascade="all, delete-orphan" ) + @property + def sorted_clins(self): + return sorted(self.clins, key=lambda clin: (clin.number[1:], clin.number[0])) + @hybrid_property def pdf(self): return self._pdf diff --git a/templates/fragments/task_order_review.html b/templates/fragments/task_order_review.html index 80029eb8..29b013c5 100644 --- a/templates/fragments/task_order_review.html +++ b/templates/fragments/task_order_review.html @@ -49,7 +49,7 @@ - {% for clin in task_order.clins %} + {% for clin in task_order.sorted_clins %} {{ clin.number }} {{ clin.type }} diff --git a/tests/models/test_task_order.py b/tests/models/test_task_order.py index 88dd8aa5..19a2a6af 100644 --- a/tests/models/test_task_order.py +++ b/tests/models/test_task_order.py @@ -52,6 +52,25 @@ def test_task_order_clins_are_completed(): assert not TaskOrderFactory.create(clins=[]).clins_are_completed +def test_clin_sorting(): + task_order = TaskOrderFactory.create( + clins=[ + CLINFactory.create(number="0002"), + CLINFactory.create(number="0001"), + CLINFactory.create(number="1001"), + CLINFactory.create(number="1002"), + CLINFactory.create(number="2001"), + ] + ) + assert [clin.number for clin in task_order.sorted_clins] == [ + "0001", + "1001", + "2001", + "0002", + "1002", + ] + + class TestTaskOrderStatus: @patch("atst.models.TaskOrder.is_completed", new_callable=PropertyMock) @patch("atst.models.TaskOrder.is_signed", new_callable=PropertyMock)