Merge branch 'staging' into state-machine-error-handling

This commit is contained in:
tomdds 2020-02-18 13:08:33 -05:00 committed by GitHub
commit b7d044b3b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 160 additions and 197 deletions

View File

@ -103,7 +103,7 @@ commands:
--password $AZURE_SP_PASSWORD \
--username $AZURE_SP
echo "Successfully logged in to Azure CLI."
az acr login --name $AZURE_REGISTRY
az acr login --name $AZURE_REGISTRY | grep "Succeeded"
- run:
name: Install kubectl
command: |

View File

@ -1,7 +1,7 @@
import os
import re
from configparser import ConfigParser
from datetime import datetime
import pendulum
from flask import Flask, request, g, session, url_for as flask_url_for
from flask_session import Session
import redis
@ -187,11 +187,11 @@ def map_config(config):
"CELERY_RESULT_EXPIRES": 0,
"CELERY_RESULT_EXTENDED": True,
"OFFICE_365_DOMAIN": "onmicrosoft.com",
"CONTRACT_START_DATE": datetime.strptime(
config.get("default", "CONTRACT_START_DATE"), "%Y-%m-%d"
"CONTRACT_START_DATE": pendulum.from_format(
config.get("default", "CONTRACT_START_DATE"), "YYYY-MM-DD"
).date(),
"CONTRACT_END_DATE": datetime.strptime(
config.get("default", "CONTRACT_END_DATE"), "%Y-%m-%d"
"CONTRACT_END_DATE": pendulum.from_format(
config.get("default", "CONTRACT_END_DATE"), "YYYY-MM-DD"
).date(),
"SESSION_COOKIE_SECURE": config.getboolean("default", "SESSION_COOKIE_SECURE"),
}

View File

@ -4,7 +4,6 @@ import hashlib
import logging
from OpenSSL import crypto, SSL
from datetime import datetime
from flask import current_app as app
from .util import load_crl_locations_cache, serialize_crl_locations_cache, CRL_LIST

View File

@ -1,5 +1,5 @@
from datetime import datetime, timedelta
from uuid import uuid4
import pendulum
class FileService:
@ -39,7 +39,7 @@ class AzureFileService(FileService):
self.account_name = config["AZURE_ACCOUNT_NAME"]
self.storage_key = config["AZURE_STORAGE_KEY"]
self.container_name = config["AZURE_TO_BUCKET_NAME"]
self.timeout = timedelta(seconds=config["PERMANENT_SESSION_LIFETIME"])
self.timeout = config["PERMANENT_SESSION_LIFETIME"]
from azure.storage.common import CloudStorageAccount
from azure.storage.blob import BlobSasPermissions
@ -68,7 +68,7 @@ class AzureFileService(FileService):
self.container_name,
object_name,
permission=self.BlobSasPermissions(create=True),
expiry=datetime.utcnow() + self.timeout,
expiry=pendulum.now(tz="utc").add(self.timeout),
protocol="https",
)
return ({"token": sas_token}, object_name)
@ -81,7 +81,7 @@ class AzureFileService(FileService):
container_name=self.container_name,
blob_name=object_name,
permission=self.BlobPermissions(read=True),
expiry=datetime.utcnow() + self.timeout,
expiry=pendulum.now(tz="utc").add(self.timeout),
content_disposition=f"attachment; filename={filename}",
protocol="https",
)

View File

@ -1,5 +1,5 @@
import datetime
from sqlalchemy.orm.exc import NoResultFound
import pendulum
from atst.database import db
from atst.models import ApplicationInvitation, InvitationStatus, PortfolioInvitation
@ -99,9 +99,7 @@ class BaseInvitations(object):
@classmethod
def current_expiration_time(cls):
return datetime.datetime.now() + datetime.timedelta(
minutes=cls.EXPIRATION_LIMIT_MINUTES
)
return pendulum.now(tz="utc").add(minutes=cls.EXPIRATION_LIMIT_MINUTES)
@classmethod
def _update_status(cls, invite, new_status):

View File

@ -1,5 +1,5 @@
from datetime import datetime
from sqlalchemy import or_
import pendulum
from atst.database import db
from atst.models.clin import CLIN
@ -41,8 +41,7 @@ class TaskOrders(BaseDomainClass):
@classmethod
def sign(cls, task_order, signer_dod_id):
task_order.signer_dod_id = signer_dod_id
task_order.signed_at = datetime.now()
task_order.signed_at = pendulum.now(tz="utc")
db.session.add(task_order)
db.session.commit()

View File

@ -1,6 +1,6 @@
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.exc import IntegrityError
from datetime import datetime
import pendulum
from atst.database import db
from atst.models import User
@ -111,7 +111,7 @@ class Users(object):
@classmethod
def update_last_login(cls, user):
user.last_login = datetime.now()
user.last_login = pendulum.now(tz="utc")
db.session.add(user)
db.session.commit()

View File

@ -1,5 +1,4 @@
import re
import datetime
from atst.utils.localization import translate
from flask import render_template
from jinja2 import contextfilter
@ -54,10 +53,6 @@ def formattedDate(value, formatter="%m/%d/%Y"):
return "-"
def dateFromString(value, formatter="%m/%Y"):
return datetime.datetime.strptime(value, formatter)
def pageWindow(pagination, size=2):
page = pagination.page
num_pages = pagination.pages
@ -81,7 +76,6 @@ def register_filters(app):
app.jinja_env.filters["dollars"] = dollars
app.jinja_env.filters["usPhone"] = usPhone
app.jinja_env.filters["formattedDate"] = formattedDate
app.jinja_env.filters["dateFromString"] = dateFromString
app.jinja_env.filters["pageWindow"] = pageWindow
app.jinja_env.filters["renderAuditEvent"] = renderAuditEvent
app.jinja_env.filters["withExtraParams"] = with_extra_params

View File

@ -9,7 +9,7 @@ from sqlalchemy import (
String,
)
from sqlalchemy.orm import relationship
from datetime import date
import pendulum
from atst.models.base import Base
import atst.models.mixins as mixins
@ -75,5 +75,5 @@ class CLIN(Base, mixins.TimestampsMixin):
@property
def is_active(self):
return (
self.start_date <= date.today() <= self.end_date
self.start_date <= pendulum.today() <= self.end_date
) and self.task_order.signed_at

View File

@ -1,4 +1,4 @@
import datetime
import pendulum
from enum import Enum
import secrets
@ -90,7 +90,7 @@ class InvitesMixin(object):
@property
def is_expired(self):
return (
datetime.datetime.now(self.expiration_time.tzinfo) > self.expiration_time
pendulum.now(tz=self.expiration_time.tzinfo) > self.expiration_time
and not self.status == Status.ACCEPTED
)

View File

@ -1,5 +1,4 @@
from enum import Enum
from decimal import Decimal
from sqlalchemy import Column, DateTime, ForeignKey, String
from sqlalchemy.ext.hybrid import hybrid_property
@ -141,14 +140,6 @@ class TaskOrder(Base, mixins.TimestampsMixin):
def total_contract_amount(self):
return sum((clin.total_amount for clin in self.clins if clin.total_amount))
@property
def invoiced_funds(self):
# TODO: implement this using reporting data from the CSP
if self.is_active:
return self.total_obligated_funds * Decimal(0.75)
else:
return 0
@property
def display_status(self):
if self.status == Status.UNSIGNED:

View File

@ -1,5 +1,4 @@
from datetime import datetime
import pendulum
from flask import redirect, render_template, url_for, request as http_request, g
from .blueprint import portfolios_bp
@ -56,5 +55,5 @@ def reports(portfolio_id):
),
current_obligated_funds=current_obligated_funds,
expired_task_orders=Reports.expired_task_orders(portfolio),
retrieved=datetime.now(), # mocked datetime of reporting data retrival
retrieved=pendulum.now(), # mocked datetime of reporting data retrival
)

View File

@ -1,4 +1,4 @@
import datetime as dt
import pendulum
from flask import Blueprint, render_template, g, request as http_request, redirect
from atst.forms.edit_user import EditUserForm
from atst.domain.users import Users
@ -23,8 +23,8 @@ def user():
next=next_,
form=form,
user=user,
mindate=(dt.datetime.now() - dt.timedelta(days=365)),
maxdate=dt.datetime.now(),
mindate=pendulum.now(tz="utc").subtract(days=365),
maxdate=pendulum.now(tz="utc"),
)
@ -44,6 +44,6 @@ def update_user():
form=form,
user=user,
next=next_url,
mindate=(dt.datetime.now() - dt.timedelta(days=365)),
maxdate=dt.datetime.now(),
mindate=pendulum.now(tz="utc").subtract(days=365),
maxdate=pendulum.now(tz="utc"),
)

View File

@ -1,7 +1,7 @@
# Add root application dir to the python path
import os
import sys
from datetime import timedelta, date
import pendulum
import random
from faker import Faker
from werkzeug.datastructures import FileStorage
@ -170,10 +170,9 @@ def add_members_to_portfolio(portfolio):
def add_task_orders_to_portfolio(portfolio):
today = date.today()
future = today + timedelta(days=100)
yesterday = today - timedelta(days=1)
five_days = timedelta(days=5)
today = pendulum.today()
future = today.add(days=100)
yesterday = today.subtract(days=1)
def build_pdf():
return {"filename": "sample_task_order.pdf", "object_name": str(uuid4())}
@ -192,13 +191,13 @@ def add_task_orders_to_portfolio(portfolio):
clins = [
CLINFactory.build(
task_order=unsigned_to, start_date=(today - five_days), end_date=today
task_order=unsigned_to, start_date=today.subtract(days=5), end_date=today
),
CLINFactory.build(
task_order=upcoming_to, start_date=(today + five_days), end_date=future
task_order=upcoming_to, start_date=today.add(days=5), end_date=future
),
CLINFactory.build(
task_order=expired_to, start_date=(today - five_days), end_date=yesterday
task_order=expired_to, start_date=today.subtract(days=5), end_date=yesterday
),
CLINFactory.build(
task_order=active_to,

View File

@ -20,14 +20,11 @@
.col--grow {
overflow: inherit;
display: table;
min-height: 10rem;
align-self: center;
}
&__name {
@include h1;
display: table-cell;
vertical-align: middle;
h1 {
margin: 0;

View File

@ -60,6 +60,12 @@
margin: ($gap * 2) 0;
max-width: 75rem;
&-label-helper {
font-size: $small-font-size;
margin-left: $gap;
margin-right: $gap;
}
label {
padding: 0 0 ($gap / 2) 0;
margin: 0;

View File

@ -26,7 +26,7 @@
<div class="usa-input__title">
{{ field.label | striptags }}
{% if optional %}
<span class="usa-input-label-helper">(optional)</span>
<span class="usa-input-label-helper">{{ "common.optional" | translate }}</span>
{% endif %}
{% if tooltip %}{{ Tooltip(tooltip) }}{% endif %}
{% if not field.description %}

View File

@ -27,7 +27,7 @@
<div class="usa-input__title{% if not field.description %}-inline{% endif %}">
{{ field.label | striptags}}
{% if optional %}
<span class="usa-input-label-helper">(optional)</span>
<span class="usa-input-label-helper">{{ "common.optional" | translate }}</span>
{% endif %}
{% if tooltip %}{{ Tooltip(tooltip) }}{% endif %}
</div>

View File

@ -40,7 +40,7 @@
<div class="usa-input__title">
{{ label }}
{% if optional and showOptional %}
<span class="usa-input-label-helper">(optional)</span>
<span class="usa-input-label-helper">{{ "common.optional" | translate }}</span>
{% endif %}
{% if tooltip and not disabled %}
{{ Tooltip(tooltip, tooltip_title) }}

View File

@ -17,36 +17,37 @@
<h1>{{ portfolio.name }}</h1>
</div>
</div>
<div class='row links'>
{% if user_can(permissions.VIEW_PORTFOLIO_ADMIN) %}
<div class="col">
<div class='row links'>
{% if user_can(permissions.VIEW_PORTFOLIO_ADMIN) %}
{{ Link(
icon='cog',
text='navigation.portfolio_navigation.breadcrumbs.admin' | translate,
url=url_for("portfolios.admin", portfolio_id=portfolio.id),
active=request.url_rule.endpoint == "portfolios.admin",
) }}
{% endif %}{% if user_can(permissions.VIEW_PORTFOLIO_FUNDING) %}
{{ Link(
icon='funding',
text='navigation.portfolio_navigation.breadcrumbs.funding' | translate,
url=url_for("task_orders.portfolio_funding", portfolio_id=portfolio.id),
active=request.url_rule.endpoint in ["task_orders.portfolio_funding", "task_orders.view_task_order", "task_orders.form_step_one_add_pdf", "task_orders.submit_form_step_one_add_pdf", "task_orders.form_step_two_add_number", "task_orders.submit_form_step_two_add_number", "task_orders.form_step_three_add_clins", "task_orders.submit_form_step_three_add_clins", "task_orders.form_step_four_review", "task_orders.form_step_five_confirm_signature"],
) }}
{% endif %}
{{ Link(
icon='cog',
text='navigation.portfolio_navigation.breadcrumbs.admin' | translate,
url=url_for("portfolios.admin", portfolio_id=portfolio.id),
active=request.url_rule.endpoint == "portfolios.admin",
icon='applications',
text='navigation.portfolio_navigation.breadcrumbs.applications' | translate,
url=url_for("applications.portfolio_applications", portfolio_id=portfolio.id),
active=request.url_rule.endpoint in ["applications.portfolio_applications", "applications.settings"],
) }}
{% endif %}{% if user_can(permissions.VIEW_PORTFOLIO_FUNDING) %}
{{ Link(
icon='funding',
text='navigation.portfolio_navigation.breadcrumbs.funding' | translate,
url=url_for("task_orders.portfolio_funding", portfolio_id=portfolio.id),
active=request.url_rule.endpoint in ["task_orders.portfolio_funding", "task_orders.view_task_order", "task_orders.form_step_one_add_pdf", "task_orders.submit_form_step_one_add_pdf", "task_orders.form_step_two_add_number", "task_orders.submit_form_step_two_add_number", "task_orders.form_step_three_add_clins", "task_orders.submit_form_step_three_add_clins", "task_orders.form_step_four_review", "task_orders.form_step_five_confirm_signature"],
) }}
{% endif %}
{{ Link(
icon='applications',
text='navigation.portfolio_navigation.breadcrumbs.applications' | translate,
url=url_for("applications.portfolio_applications", portfolio_id=portfolio.id),
active=request.url_rule.endpoint in ["applications.portfolio_applications", "applications.settings"],
) }}
{% if user_can(permissions.VIEW_PORTFOLIO_REPORTS) %}
{{ Link(
icon='chart-pie',
text='navigation.portfolio_navigation.breadcrumbs.reports' | translate,
url=url_for("portfolios.reports", portfolio_id=portfolio.id),
active=request.url_rule.endpoint == "portfolios.reports",
) }}
{% endif %}
{% if user_can(permissions.VIEW_PORTFOLIO_REPORTS) %}
{{ Link(
icon='chart-pie',
text='navigation.portfolio_navigation.breadcrumbs.reports' | translate,
url=url_for("portfolios.reports", portfolio_id=portfolio.id),
active=request.url_rule.endpoint == "portfolios.reports",
) }}
{% endif %}
</div>
</div>
</div>

View File

@ -8,8 +8,8 @@
{% set expended_funds = task_order.invoiced_funds %}
<div>
<section class="row">
<div class='col col--grow summary-item'>
<section class="usa-grid">
<div class='usa-width-one-third summary-item'>
<h4 class="summary-item__header">
<span class="summary-item__header-text">{{ 'task_orders.summary.total' | translate }}</span>
{{ Tooltip(("task_orders.review.tooltip.total_value" | translate), title="", classes="icon-tooltip--tight") }}
@ -18,7 +18,7 @@
{{ contract_amount | dollars }}
</p>
</div>
<div class='col col--grow summary-item'>
<div class='usa-width-one-third summary-item'>
<h4 class="summary-item__header">
<span class="summary-item__header-text">{{ 'task_orders.summary.obligated' | translate }}</span>
{{ Tooltip(("task_orders.review.tooltip.obligated_funds" | translate), title="", classes="icon-tooltip--tight") }}
@ -27,15 +27,6 @@
{{ obligated_funds | dollars }}
</p>
</div>
<div class='col col--grow summary-item'>
<h4 class="summary-item__header">
<span class="summary-item__header-text">{{ 'task_orders.summary.expended' | translate }}</span>
{{ Tooltip(("task_orders.review.tooltip.expended_funds" | translate), title="", classes="icon-tooltip--tight") }}
</h4>
<p class="summary-item__value--large">
{{ expended_funds | dollars }}
</p>
</div>
</section>
<hr>
<section>

View File

@ -34,8 +34,8 @@
<div class="accordion__content--list-item">
<h4><a href="{{ url_for('task_orders.view_task_order', task_order_id=task_order.id) }}">{{ to_number }} {{ Icon("caret_right", classes="icon--tiny icon--primary" ) }}</a></h4>
{% if status != 'Expired' -%}
<div class="row">
<div class="col col--grow">
<div class="usa-grid">
<div class="usa-width-one-fourth">
<h5>
Current Period of Performance
</h5>
@ -45,18 +45,14 @@
{{ task_order.end_date | formattedDate(formatter="%b %d, %Y") }}
</p>
</div>
<div class="col col--grow">
<div class="usa-width-one-fourth">
<h5>Total Value</h5>
<p>{{ task_order.total_contract_amount | dollars }}</p>
</div>
<div class="col col--grow">
<div class="usa-width-one-fourth">
<h5>Total Obligated</h5>
<p>{{ task_order.total_obligated_funds | dollars }}</p>
</div>
<div class="col col--grow">
<h5>Total Expended</h5>
<p>{{ task_order.invoiced_funds | dollars }}</p>
</div>
</div>
{%- endif %}
</div>

View File

@ -13,7 +13,7 @@ import tests.factories as factories
from tests.mocks import PDF_FILENAME, PDF_FILENAME2
from tests.utils import FakeLogger, FakeNotificationSender
from datetime import datetime, timedelta
import pendulum
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography import x509
from cryptography.hazmat.backends import default_backend
@ -175,7 +175,7 @@ def extended_financial_verification_data(pdf_upload):
return {
"funding_type": "RDTE",
"funding_type_other": "other",
"expiration_date": "1/1/{}".format(datetime.date.today().year + 1),
"expiration_date": "1/1/{}".format(pendulum.today().year + 1),
"clin_0001": "50000",
"clin_0003": "13000",
"clin_1001": "30000",
@ -214,7 +214,6 @@ def make_x509():
if signer_key is None:
signer_key = private_key
one_day = timedelta(1, 0, 0)
public_key = private_key.public_key()
builder = x509.CertificateBuilder()
builder = builder.subject_name(
@ -227,8 +226,8 @@ def make_x509():
builder = builder.add_extension(
x509.BasicConstraints(ca=True, path_length=None), critical=True
)
builder = builder.not_valid_before(datetime.today() - (one_day * 2))
builder = builder.not_valid_after(datetime.today() + (one_day * 30))
builder = builder.not_valid_before(pendulum.today().subtract(days=2))
builder = builder.not_valid_after(pendulum.today().add(days=30))
builder = builder.serial_number(x509.random_serial_number())
builder = builder.public_key(public_key)
certificate = builder.sign(
@ -249,13 +248,12 @@ def make_crl():
cn="ATAT",
expired_serials=None,
):
one_day = timedelta(1, 0, 0)
builder = x509.CertificateRevocationListBuilder()
builder = builder.issuer_name(
x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)])
)
last_update = datetime.today() + (one_day * last_update_days)
next_update = datetime.today() + (one_day * next_update_days)
last_update = pendulum.today().add(days=last_update_days)
next_update = pendulum.today().add(days=next_update_days)
builder = builder.last_update(last_update)
builder = builder.next_update(next_update)
if expired_serials:

View File

@ -1,4 +1,4 @@
from datetime import datetime, timedelta
import pendulum
import pytest
from uuid import uuid4
@ -200,8 +200,8 @@ def test_update_does_not_duplicate_names_within_portfolio():
def test_get_applications_pending_creation():
now = datetime.now()
later = now + timedelta(minutes=30)
now = pendulum.now(tz="utc")
later = now.add(minutes=30)
portfolio1 = PortfolioFactory.create(state="COMPLETED")
app_ready = ApplicationFactory.create(portfolio=portfolio1)

View File

@ -1,6 +1,6 @@
import datetime
import pytest
import re
import pendulum
from atst.domain.audit_log import AuditLog
from atst.domain.invitations import (
@ -53,7 +53,7 @@ def test_accept_expired_invitation():
portfolio = PortfolioFactory.create()
role = PortfolioRoleFactory.create(portfolio=portfolio)
increment = PortfolioInvitations.EXPIRATION_LIMIT_MINUTES + 1
expiration_time = datetime.datetime.now() - datetime.timedelta(minutes=increment)
expiration_time = pendulum.now(tz="utc").subtract(minutes=increment)
invite = PortfolioInvitationFactory.create(
expiration_time=expiration_time,
status=InvitationStatus.PENDING,

View File

@ -1,5 +1,5 @@
import pytest
from datetime import date, datetime, timedelta
import pendulum
from decimal import Decimal
from atst.domain.exceptions import AlreadyExistsError
@ -15,16 +15,16 @@ def test_create_adds_clins():
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "12312",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"start_date": pendulum.date(2020, 1, 1),
"end_date": pendulum.date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"total_amount": Decimal("10000"),
},
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "12312",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"start_date": pendulum.date(2020, 1, 1),
"end_date": pendulum.date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"total_amount": Decimal("10000"),
},
@ -45,16 +45,16 @@ def test_update_adds_clins():
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "12312",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"start_date": pendulum.date(2020, 1, 1),
"end_date": pendulum.date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"total_amount": Decimal("10000"),
},
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "12312",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"start_date": pendulum.date(2020, 1, 1),
"end_date": pendulum.date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"total_amount": Decimal("10000"),
},
@ -77,16 +77,16 @@ def test_update_does_not_duplicate_clins():
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "123",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"start_date": pendulum.date(2020, 1, 1),
"end_date": pendulum.date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"total_amount": Decimal("10000"),
},
{
"jedi_clin_type": "JEDI_CLIN_1",
"number": "111",
"start_date": date(2020, 1, 1),
"end_date": date(2021, 1, 1),
"start_date": pendulum.date(2020, 1, 1),
"end_date": pendulum.date(2021, 1, 1),
"obligated_amount": Decimal("5000"),
"total_amount": Decimal("10000"),
},
@ -114,9 +114,9 @@ def test_delete_task_order_with_clins(session):
def test_task_order_sort_by_status():
today = date.today()
yesterday = today - timedelta(days=1)
future = today + timedelta(days=100)
today = pendulum.today()
yesterday = today.subtract(days=1)
future = today.add(days=100)
initial_to_list = [
# Draft
@ -184,12 +184,12 @@ def test_allows_alphanumeric_number():
def test_get_for_send_task_order_files():
new_to = TaskOrderFactory.create(create_clins=[{}])
updated_to = TaskOrderFactory.create(
create_clins=[{"last_sent_at": datetime(2020, 2, 1)}],
pdf_last_sent_at=datetime(2020, 1, 1),
create_clins=[{"last_sent_at": pendulum.datetime(2020, 2, 1)}],
pdf_last_sent_at=pendulum.datetime(2020, 1, 1),
)
sent_to = TaskOrderFactory.create(
create_clins=[{"last_sent_at": datetime(2020, 1, 1)}],
pdf_last_sent_at=datetime(2020, 1, 1),
create_clins=[{"last_sent_at": pendulum.datetime(2020, 1, 1)}],
pdf_last_sent_at=pendulum.datetime(2020, 1, 1),
)
updated_and_new_task_orders = TaskOrders.get_for_send_task_order_files()

View File

@ -1,5 +1,4 @@
import pytest
from datetime import datetime
from uuid import uuid4
from atst.domain.users import Users

View File

@ -3,7 +3,7 @@ import random
import string
import factory
from uuid import uuid4
import datetime
import pendulum
from atst.forms import data
from atst.models import *
@ -56,8 +56,8 @@ def _random_date(year_min, year_max, operation):
else:
inc = random.randrange(year_min, year_max)
return datetime.date(
operation(datetime.date.today().year, inc),
return pendulum.date(
operation(pendulum.today().year, inc),
random.randrange(1, 12),
random.randrange(1, 28),
)
@ -99,8 +99,7 @@ class UserFactory(Base):
citizenship = "United States"
designation = "military"
date_latest_training = factory.LazyFunction(
lambda: datetime.date.today()
+ datetime.timedelta(days=-(random.randrange(1, 365)))
lambda: pendulum.today().add(days=-(random.randrange(1, 365)))
)
@classmethod
@ -341,7 +340,7 @@ class CLINFactory(Base):
task_order = factory.SubFactory(TaskOrderFactory)
number = factory.LazyFunction(random_clin_number)
start_date = datetime.date.today()
start_date = pendulum.today()
end_date = factory.LazyFunction(random_future_date)
total_amount = factory.LazyFunction(lambda *args: random.randint(50000, 999999))
obligated_amount = factory.LazyFunction(lambda *args: random.randint(100, 50000))

View File

@ -1,4 +1,4 @@
import datetime
import pendulum
from dateutil.relativedelta import relativedelta
from flask import current_app as app
@ -17,8 +17,8 @@ def test_clin_form_jedi_clin_type():
def test_clin_form_start_date_before_end_date():
invalid_start = datetime.date(2020, 12, 12)
invalid_end = datetime.date(2020, 1, 1)
invalid_start = pendulum.date(2020, 12, 12)
invalid_end = pendulum.date(2020, 1, 1)
invalid_clin = factories.CLINFactory.create(
start_date=invalid_start, end_date=invalid_end
)
@ -28,8 +28,8 @@ def test_clin_form_start_date_before_end_date():
translate("forms.task_order.pop_errors.date_order")
in clin_form.start_date.errors
)
valid_start = datetime.date(2020, 1, 1)
valid_end = datetime.date(2020, 12, 12)
valid_start = pendulum.date(2020, 1, 1)
valid_end = pendulum.date(2020, 12, 12)
valid_clin = factories.CLINFactory.create(
start_date=valid_start, end_date=valid_end
)
@ -81,8 +81,8 @@ def test_clin_form_obligated_greater_than_total():
invalid_clin = factories.CLINFactory.create(
total_amount=0,
obligated_amount=1,
start_date=datetime.date(2019, 9, 15),
end_date=datetime.date(2020, 9, 14),
start_date=pendulum.date(2019, 9, 15),
end_date=pendulum.date(2020, 9, 14),
)
invalid_clin_form = CLINForm(obj=invalid_clin)
assert not invalid_clin_form.validate()
@ -95,8 +95,8 @@ def test_clin_form_dollar_amounts_out_of_range():
invalid_clin = factories.CLINFactory.create(
total_amount=-1,
obligated_amount=1000000001,
start_date=datetime.date(2019, 9, 15),
end_date=datetime.date(2020, 9, 14),
start_date=pendulum.date(2019, 9, 15),
end_date=pendulum.date(2020, 9, 14),
)
invalid_clin_form = CLINForm(obj=invalid_clin)
assert not invalid_clin_form.validate()

View File

@ -1,4 +1,5 @@
import pytest
import pendulum
from atst.domain.permission_sets import PermissionSets
from atst.domain.environment_roles import EnvironmentRoles
@ -61,7 +62,7 @@ def test_environment_roles():
def test_display_status():
yesterday = datetime.date.today() - datetime.timedelta(days=1)
yesterday = pendulum.today().subtract(days=1)
expired_invite = ApplicationInvitationFactory.create(expiration_time=yesterday)
assert expired_invite.role.display_status == "invite_expired"

View File

@ -6,7 +6,6 @@ from tests.factories import (
random_future_date,
random_past_date,
)
import datetime
import pendulum
from decimal import Decimal
import pytest
@ -83,7 +82,7 @@ def test_funding_duration(session):
portfolio=portfolio,
signed_at=random_past_date(),
create_clins=[
{"start_date": datetime.datetime.now(), "end_date": funding_end_date,}
{"start_date": pendulum.now(tz="utc"), "end_date": funding_end_date,}
],
)
@ -106,7 +105,7 @@ def test_days_remaining(session):
assert (
portfolio.days_to_funding_expiration
== (funding_end_date - datetime.date.today()).days
== (funding_end_date - pendulum.today()).days
)
# empty portfolio
@ -121,8 +120,8 @@ def test_active_task_orders(session):
signed_at=random_past_date(),
create_clins=[
{
"start_date": datetime.date(2019, 1, 1),
"end_date": datetime.date(2019, 10, 31),
"start_date": pendulum.date(2019, 1, 1),
"end_date": pendulum.date(2019, 10, 31),
}
],
)

View File

@ -1,4 +1,4 @@
import datetime
import pendulum
from atst.models import InvitationStatus, PortfolioRoleStatus
@ -17,7 +17,7 @@ def test_expired_invite_is_not_revokable():
portfolio=portfolio, user=user, status=PortfolioRoleStatus.PENDING
)
invite = PortfolioInvitationFactory.create(
expiration_time=datetime.datetime.now() - datetime.timedelta(minutes=60),
expiration_time=pendulum.now(tz="utc").subtract(minutes=60),
role=portfolio_role,
)
assert not invite.is_revokable

View File

@ -1,5 +1,5 @@
import pytest
import datetime
import pendulum
from atst.domain.environments import Environments
from atst.domain.portfolios import Portfolios
@ -204,7 +204,7 @@ def test_status_when_invitation_is_expired():
PortfolioInvitationFactory.create(
role=portfolio_role,
status=InvitationStatus.PENDING,
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
expiration_time=pendulum.now(tz="utc").subtract(seconds=1),
)
assert portfolio_role.display_status == "invite_expired"

View File

@ -1,6 +1,6 @@
from werkzeug.datastructures import FileStorage
import pytest
from datetime import date
import pendulum
from unittest.mock import patch, PropertyMock
import pendulum
@ -13,11 +13,11 @@ from tests.mocks import PDF_FILENAME
def test_period_of_performance_is_first_to_last_clin():
start_date = date(2019, 6, 6)
end_date = date(2020, 6, 6)
start_date = pendulum.date(2019, 6, 6)
end_date = pendulum.date(2020, 6, 6)
intermediate_start_date = date(2019, 7, 1)
intermediate_end_date = date(2020, 3, 1)
intermediate_start_date = pendulum.date(2019, 7, 1)
intermediate_end_date = pendulum.date(2020, 3, 1)
task_order = TaskOrderFactory.create(
clins=[

View File

@ -1,6 +1,6 @@
import pytest
from sqlalchemy.exc import InternalError
from datetime import datetime
import pendulum
from atst.database import db
from atst.domain.users import Users
@ -44,7 +44,7 @@ def test_deleted_application_roles_are_ignored(session):
def test_does_not_log_user_update_when_updating_last_login(mock_logger):
user = UserFactory.create()
user.last_login = datetime.now()
user.last_login = pendulum.now(tz="utc")
db.session.add(user)
db.session.commit()
assert "Audit Event update" not in mock_logger.messages

View File

@ -1,4 +1,4 @@
import datetime
import pendulum
import uuid
from unittest.mock import Mock, patch
@ -613,7 +613,7 @@ def test_filter_environment_roles():
user = UserFactory.create()
# need to set the time created to yesterday, otherwise the original invite and resent
# invite have the same time_created and then we can't rely on time to order the invites
yesterday = datetime.date.today() - datetime.timedelta(days=1)
yesterday = pendulum.today().subtract(days=1)
invite = ApplicationInvitationFactory.create(
user=user, time_created=yesterday, email="original@example.com"
)

View File

@ -1,4 +1,4 @@
import datetime
import pendulum
from unittest.mock import Mock
from flask import url_for
@ -123,7 +123,7 @@ def test_user_accepts_expired_invite(client, user_session):
user_id=user.id,
role=ws_role,
status=InvitationStatus.REJECTED_EXPIRED,
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
expiration_time=pendulum.now(tz="utc").subtract(seconds=1),
)
user_session(user)
response = client.get(
@ -143,7 +143,7 @@ def test_revoke_invitation(client, user_session):
user_id=user.id,
role=ws_role,
status=InvitationStatus.REJECTED_EXPIRED,
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
expiration_time=pendulum.now(tz="utc").subtract(seconds=1),
)
user_session(portfolio.owner)
response = client.post(
@ -169,7 +169,7 @@ def test_user_can_only_revoke_invites_in_their_portfolio(client, user_session):
user_id=user.id,
role=portfolio_role,
status=InvitationStatus.REJECTED_EXPIRED,
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
expiration_time=pendulum.now(tz="utc").subtract(seconds=1),
)
user_session(portfolio.owner)
response = client.post(
@ -199,7 +199,7 @@ def test_user_can_only_resend_invites_in_their_portfolio(
user_id=user.id,
role=portfolio_role,
status=InvitationStatus.REJECTED_EXPIRED,
expiration_time=datetime.datetime.now() - datetime.timedelta(seconds=1),
expiration_time=pendulum.now(tz="utc").subtract(seconds=1),
)
user_session(portfolio.owner)
response = client.post(

View File

@ -1,7 +1,5 @@
from datetime import date
from flask import url_for
import pytest
from datetime import timedelta, date
from atst.domain.permission_sets import PermissionSets
from atst.domain.task_orders import TaskOrders

View File

@ -1,6 +1,6 @@
import pytest
from flask import url_for, get_flashed_messages
from datetime import timedelta, date
import pendulum
from uuid import uuid4
from atst.domain.task_orders import TaskOrders
@ -339,7 +339,7 @@ def test_task_orders_submit_task_order(client, user_session, task_order):
)
assert response.status_code == 302
active_start_date = date.today() - timedelta(days=1)
active_start_date = pendulum.today().subtract(days=1)
active_task_order = TaskOrderFactory(portfolio=task_order.portfolio)
CLINFactory(task_order=active_task_order, start_date=active_start_date)
assert active_task_order.status == TaskOrderStatus.UNSIGNED
@ -348,7 +348,7 @@ def test_task_orders_submit_task_order(client, user_session, task_order):
)
assert active_task_order.status == TaskOrderStatus.ACTIVE
upcoming_start_date = date.today() + timedelta(days=1)
upcoming_start_date = pendulum.today().add(days=1)
upcoming_task_order = TaskOrderFactory(portfolio=task_order.portfolio)
CLINFactory(task_order=upcoming_task_order, start_date=upcoming_start_date)
assert upcoming_task_order.status == TaskOrderStatus.UNSIGNED

View File

@ -3,11 +3,11 @@ from urllib.parse import urlparse
import pytest
from datetime import datetime
import pendulum
from flask import session, url_for
from cryptography.hazmat.primitives.serialization import Encoding
from atst.domain.users import Users
from atst.domain.permission_sets import PermissionSets
from atst.domain.exceptions import NotFoundError
from atst.domain.authnid.crl import CRLInvalidException
from atst.domain.auth import UNPROTECTED_ROUTES
@ -262,7 +262,7 @@ def test_error_on_invalid_crl(client, monkeypatch):
def test_last_login_set_when_user_logs_in(client, monkeypatch):
last_login = datetime.now()
last_login = pendulum.now(tz="utc")
user = UserFactory.create(last_login=last_login)
monkeypatch.setattr(
"atst.domain.authnid.AuthenticationContext.authenticate", lambda *args: True
@ -270,7 +270,7 @@ def test_last_login_set_when_user_logs_in(client, monkeypatch):
monkeypatch.setattr(
"atst.domain.authnid.AuthenticationContext.get_user", lambda *args: user
)
response = _login(client)
_login(client)
assert session["last_login"]
assert user.last_login > session["last_login"]
assert isinstance(session["last_login"], datetime)

View File

@ -51,6 +51,7 @@ common:
lorem: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
name: Name
next: Next
optional: Optional
previous: Previous
save: Save
save_changes: Save Changes
@ -506,12 +507,12 @@ portfolios:
archive_button: Delete member
reports:
days_remaining:
header: Days Remaining
header: Days remaining
toolip: Days remaining are the days of funding remaining in the portfolio.
duration:
header: Funding Duration
header: Funding duration
tooltip: Funding duration is the period of time that there is a valid task order funding the portfolio.
estimate_warning: Reports displayed in JEDI are estimates and not a system of record.
estimate_warning: Reports displayed in JEDI are estimates and not a system of record. To manage your costs, go to Azure by selecting the Login to Azure button above.
total_value:
header: Total Portfolio Value
tooltip: Total portfolio value is all obligated funds for current and upcoming task orders in this portfolio.
@ -533,7 +534,6 @@ task_orders:
tooltip:
obligated_funds: Funds committed to fund your portfolio. This may represent 100% of your total Task Order value, or a portion of it.
total_value: All obligated and projected funds for the Task Orders Base and Option CLINs.
expended_funds: All funds spent from the Task Order so far.
form:
add_clin: Add Another CLIN
add_to_header: Enter the Task Order number
@ -593,7 +593,6 @@ task_orders:
summary:
obligated: Total Obligated
total: Total Value
expended: Total Expended
JEDICLINType:
JEDI_CLIN_1: "IDIQ CLIN 0001 Unclassified IaaS/PaaS"
JEDI_CLIN_2: "IDIQ CLIN 0002 Classified IaaS/PaaS"