diff --git a/microsetta_private_api/admin/admin_impl.py b/microsetta_private_api/admin/admin_impl.py index 1369a7f3d..29dbff725 100644 --- a/microsetta_private_api/admin/admin_impl.py +++ b/microsetta_private_api/admin/admin_impl.py @@ -415,7 +415,7 @@ def query_barcode_stats(body, token_info, strip_sampleid): validate_admin_access(token_info) barcodes = body["sample_barcodes"] if len(barcodes) > 1000: - return jsonify({"message": "Too manny barcodes requested"}), 400 + return jsonify({"message": "Too many barcodes requested"}), 400 summary = per_sample(None, barcodes, strip_sampleid) return jsonify(summary), 200 diff --git a/microsetta_private_api/admin/daklapack_communication.py b/microsetta_private_api/admin/daklapack_communication.py index 8cbef86fc..efb12b78a 100644 --- a/microsetta_private_api/admin/daklapack_communication.py +++ b/microsetta_private_api/admin/daklapack_communication.py @@ -8,8 +8,6 @@ SERVER_CONFIG["daklapack_subscription_key_val"] } -ORDER_HOLD_TEMPLATE_PATH = "email/daklapack_fulfillment_hold_request" - def _get_daklapack_oauth2_session(): # run the "Resource Owner Client Credentials Grant Type" oauth2 workflow @@ -26,29 +24,77 @@ def _get_daklapack_oauth2_session(): def post_daklapack_order(payload): + return _post_to_daklapack_api("/api/Orders/", payload) + + +def post_daklapack_order_archive(payload): + return _post_to_daklapack_api("/api/Orders/Archive", payload) + + +def _post_to_daklapack_api(url_suffix, payload): oauth_session = _get_daklapack_oauth2_session() + + dak_order_post_url = f"{SERVER_CONFIG['daklapack_api_base_url']}" \ + f"{url_suffix}" + # the json parameter sets the content-type in the headers # to application/json, whereas if used data parameter, would have to set # content-type manually - dak_order_post_url = f"{SERVER_CONFIG['daklapack_api_base_url']}" \ - f"/api/orders" result = oauth_session.post( dak_order_post_url, json=payload, headers=DAK_HEADERS) + + if result.status_code >= 300: + raise ValueError(f"Posting {payload} to {url_suffix} received " + f"status code {result.status_code}: {result.json}") + return result + + +def send_daklapack_order_errors_report_email(errors_list): + result = None + if len(errors_list) > 0: + template_args = {"errors": errors_list} + email_subject = "Daklapack order errors" + + result = _send_daklapack_email(template_args, email_subject, + "daklapack_errors_report_email", + "email/daklapack_order_errors_report", + "DAK_ORDER_ERRORS_REPORT") + return result + + +def send_daklapack_polling_errors_report_email(errors_list): + result = None + if len(errors_list) > 0: + template_args = {"errors": errors_list} + email_subject = "Daklapack polling code errors" + + result = _send_daklapack_email(template_args, email_subject, + "daklapack_errors_report_email", + "email/daklapack_polling_errors_report", + "DAK_POLLING_ERRORS_REPORT") return result def send_daklapack_hold_email(daklapack_order): + template_args = {"order_id": daklapack_order.id, + "fulfillment_hold_msg": + daklapack_order.fulfillment_hold_msg} + email_subject = f"Hold fulfillment of order {daklapack_order.id}" + + return _send_daklapack_email(template_args, email_subject, + "daklapack_service_email", + "email/daklapack_fulfillment_hold_request", + "DAK_ORDER_HOLD") + + +def _send_daklapack_email(template_args, email_subject, email_config_key, + template_path, email_subtype): try: - template_args = {"order_id": daklapack_order.id, - "fulfillment_hold_msg": - daklapack_order.fulfillment_hold_msg} - email_subject = f"Hold fulfillment of order {daklapack_order.id}" - dak_service_email = SERVER_CONFIG["daklapack_service_email"] + errors_report_email = SERVER_CONFIG[email_config_key] celery_send_email.apply_async( - args=[dak_service_email, email_subject, - ORDER_HOLD_TEMPLATE_PATH, + args=[errors_report_email, email_subject, template_path, list(template_args.keys()), template_args, - "EMAIL", "DAK_ORDER_HOLD"]) + "EMAIL", email_subtype]) email_success = True except Exception: # noqa email_success = False diff --git a/microsetta_private_api/admin/daklapack_polling.py b/microsetta_private_api/admin/daklapack_polling.py index 111b96b38..5944d4f65 100644 --- a/microsetta_private_api/admin/daklapack_polling.py +++ b/microsetta_private_api/admin/daklapack_polling.py @@ -74,14 +74,14 @@ def make_error_str(ex): curr_page += 1 # end while - - # email a list of any failed orders to address in the config - # dc.send_daklapack_order_errors_report_email(results[ERROR_STATUS]) except Exception as outer_ex: results[CODE_ERROR].append(make_error_str(outer_ex)) + # email a list of any failed orders to address in the config + dc.send_daklapack_order_errors_report_email(results[ERROR_STATUS]) + # email a list of any encountered exceptions to address in the config - # dc.send_daklapack_polling_errors_report_email(results[CODE_ERROR]) + dc.send_daklapack_polling_errors_report_email(results[CODE_ERROR]) return results @@ -100,7 +100,10 @@ def _process_single_order(curr_order_id, curr_status, curr_creation_date): per_article_info = process_order_articles( per_order_admin_repo, curr_order_id, curr_status, curr_creation_date) - # end if error or sent + + if curr_status == ERROR_STATUS: + # archive the errored order + dc.post_daklapack_order_archive({"orderIds": [curr_order_id]}) per_order_t.commit() diff --git a/microsetta_private_api/admin/tests/test_daklapack_polling.py b/microsetta_private_api/admin/tests/test_daklapack_polling.py index 82e1117f2..d774adb05 100644 --- a/microsetta_private_api/admin/tests/test_daklapack_polling.py +++ b/microsetta_private_api/admin/tests/test_daklapack_polling.py @@ -638,7 +638,25 @@ def test_poll_dak_orders(self): 200, articles_for_orders[0]), make_test_response( 200, articles_for_orders[1])] - real_out = poll_dak_orders() + with patch("microsetta_private_api.admin." + "daklapack_communication." + "post_daklapack_order_archive") as mock_archive: + mock_archive.side_effect = [make_test_response( + 200, {"updated": 1})] + + with patch("microsetta_private_api.admin." + "daklapack_communication.send_" + "daklapack_order_errors_report_email") as \ + mock_order_email: + mock_order_email.side_effect = [True] + + with patch("microsetta_private_api.admin." + "daklapack_communication.send_daklapack" + "_polling_errors_report_email") as \ + mock_polling_email: + mock_polling_email.side_effect = [True] + + real_out = poll_dak_orders() # for three incomplete orders that saved, check status in db self._check_last_polling_status( diff --git a/microsetta_private_api/celery_utils.py b/microsetta_private_api/celery_utils.py index ad233df9c..d103a1423 100644 --- a/microsetta_private_api/celery_utils.py +++ b/microsetta_private_api/celery_utils.py @@ -32,6 +32,10 @@ def __call__(self, *args, **kwargs): "update_vioscreen_sessions": { "task": "microsetta_private_api.util.vioscreen.update_session_detail", # noqa "schedule": 60 * 60 * 24 # every 24 hours + }, + "poll_daklapack_orders": { + "task": "microsetta_private_api.admin.daklapack_polling.poll_dak_orders", # noqa + "schedule": 60 * 60 * 24 # every 24 hours } } diff --git a/microsetta_private_api/model/log_event.py b/microsetta_private_api/model/log_event.py index 5a68c78b6..67b45001a 100644 --- a/microsetta_private_api/model/log_event.py +++ b/microsetta_private_api/model/log_event.py @@ -36,6 +36,10 @@ class EventSubtype(Enum): EMAIL_NO_SOURCE = "no_associated_source" # Fulfillment of a daklapack order must be held DAK_ORDER_HOLD = "daklapack_order_hold" + # Daklapack order polling idenfitied orders with errors + DAK_ORDER_ERRORS_REPORT = "daklapack_orders_error_report" + # Daklapack polling encountered code errors + DAK_POLLING_ERRORS_REPORT = "daklapack_polling_errors_report" # Pester daniel if for what are expected to be unusual situations PESTER_DANIEL = "pester_daniel" # for project per-sample summaries diff --git a/microsetta_private_api/server_config.json b/microsetta_private_api/server_config.json index 150957c13..f8b082500 100644 --- a/microsetta_private_api/server_config.json +++ b/microsetta_private_api/server_config.json @@ -22,5 +22,6 @@ "daklapack_subscription_key_name": "dak-specific-key", "daklapack_subscription_key_val": "123abc456d89z", "daklapack_api_base_url": "https://example.com/dak_api", - "daklapack_service_email": "dak_fake@example.com" + "daklapack_service_email": "dak_fake@example.com", + "daklapack_errors_report_email": "microsetta_recipient@fake.com" } diff --git a/microsetta_private_api/templates/email/daklapack_order_errors_report.jinja2 b/microsetta_private_api/templates/email/daklapack_order_errors_report.jinja2 new file mode 100644 index 000000000..9861122da --- /dev/null +++ b/microsetta_private_api/templates/email/daklapack_order_errors_report.jinja2 @@ -0,0 +1,35 @@ + + + + + +

+Daklapack reports that the following orders have an error in their system and cannot be fulfilled. +Please identify and correct these errors and then submit replacement Daklapack orders. +

+ + + + + + + + + + + + + {% for curr_error in errors %} + + + + + + + + + {% endfor %} + +
Order IDArticle CodeSent-To AddressOrder SubmitterCreation DateStatus Description
{{ curr_error['order_id'] }}{{ curr_error['article_code'] }}{{ curr_error['sent_to_address'] }}{{ curr_error['order_submitter'] }}{{ curr_error['creation_date'] }}{{ curr_error['status_description'] }}
+ + \ No newline at end of file diff --git a/microsetta_private_api/templates/email/daklapack_polling_errors_report.jinja2 b/microsetta_private_api/templates/email/daklapack_polling_errors_report.jinja2 new file mode 100644 index 000000000..814978271 --- /dev/null +++ b/microsetta_private_api/templates/email/daklapack_polling_errors_report.jinja2 @@ -0,0 +1,16 @@ + + + + + +

+The Daklapack order status polling code encountered the following exceptions. +Please alert the development team. +

+ +{% for curr_error in errors %} +

{{ curr_error }}

+{% endfor %} + + + \ No newline at end of file