diff --git a/microsetta_admin/server.py b/microsetta_admin/server.py index d023e70..76d783c 100644 --- a/microsetta_admin/server.py +++ b/microsetta_admin/server.py @@ -921,45 +921,79 @@ def return_error(msg): f"not match expected column names" f" {expected_headers}") + # disregard empty rows + addresses_df = addresses_df.dropna(how='all').copy() + # add (same) contact phone number to every address addresses_df['phone'] = phone_number - addresses_df = addresses_df.fillna("") - temp_dict = addresses_df.to_dict(orient='index') - addresses_list = [temp_dict[n] for n in range(len(temp_dict))] - - status, post_output = APIRequest.post( - '/api/admin/daklapack_orders', - json={ - "project_ids": project_ids_list, - "article_code": dak_article_code, - "quantity": article_quantity, - "addresses": addresses_list, - "shipping_provider": shipping_provider, - "shipping_type": shipping_type, - "planned_send_date": planned_send_date, - "description": description, - "fedex_ref_1": fedex_ref_1, - "fedex_ref_2": fedex_ref_2, - "fedex_ref_3": fedex_ref_3 - } + # validate spreadsheet rows + empty_field_criteria = ( + addresses_df + .drop(columns=['insertion', 'address2']) + .isna() + .any(axis=1) ) - # if the post failed, keep track of the error so it can be displayed - if status != 200: - error_message = post_output + # display missing columns for incomplete addresses + hold_submissions_addresses = addresses_df[empty_field_criteria] + hold_submissions = pd.DataFrame({ + 'missing_columns': hold_submissions_addresses.apply( + lambda ser: ', '.join( + ser.index[ser.isna()] # find null fields + .drop(['insertion', 'address2'], errors='ignore') + ), + axis=1 + ), + 'address_dict': hold_submissions_addresses.fillna("").apply( + lambda ser: ser.to_dict(), + axis=1 + ) + }) + hold_submissions_list = hold_submissions.to_dict(orient='records') + + # prepare addresses for submission + addresses_df = addresses_df[~empty_field_criteria].fillna("") + addresses_list = addresses_df.to_dict(orient='records') + + # skip API call if no valid address + if addresses_list: + status, post_output = APIRequest.post( + '/api/admin/daklapack_orders', + json={ + "project_ids": project_ids_list, + "article_code": dak_article_code, + "quantity": article_quantity, + "addresses": addresses_list, + "shipping_provider": shipping_provider, + "shipping_type": shipping_type, + "planned_send_date": planned_send_date, + "description": description, + "fedex_ref_1": fedex_ref_1, + "fedex_ref_2": fedex_ref_2, + "fedex_ref_3": fedex_ref_3 + } + ) + + # if the post failed, keep track of the error so it can be displayed + if status != 200: + error_message = post_output + else: + order_submissions = post_output["order_submissions"] + success_submissions = [x for x in order_submissions if + x["order_success"]] + failure_submissions = [x for x in order_submissions if not + x["order_success"]] else: - order_submissions = post_output["order_submissions"] - success_submissions = [x for x in order_submissions if - x["order_success"]] - failure_submissions = [x for x in order_submissions if not - x["order_success"]] + success_submissions = [] + failure_submissions = [] return render_template('submit_daklapack_order.html', **build_login_variables(), error_message=error_message, success_submissions=success_submissions, - failure_submissions=failure_submissions) + failure_submissions=failure_submissions, + hold_submissions_list=hold_submissions_list) @app.route('/authrocket_callback') diff --git a/microsetta_admin/templates/submit_daklapack_order.html b/microsetta_admin/templates/submit_daklapack_order.html index 96e6280..0fc5e61 100644 --- a/microsetta_admin/templates/submit_daklapack_order.html +++ b/microsetta_admin/templates/submit_daklapack_order.html @@ -144,7 +144,32 @@

Submit Daklapack Order

{{ error_message }} {% endautoescape %} -{% elif success_submissions or failure_submissions %} +{% elif success_submissions or failure_submissions or hold_submissions_list %} + {% if hold_submissions_list|length > 0 %} +

+The following addresses are incomplete and NOT submitted to Daklapack. +The required fields missing are displayed below. +Please fill in all fields except for `insertion` and `address2`, then re-submit. +

+ + + + + + + + + {% for hold_submission in hold_submissions_list %} + + + + + {% endfor %} + +
Required Field(s) MissingAddress
{{ hold_submission['missing_columns'] }}{{ hold_submission['address_dict'] }}
+
+ {% endif %} + {% if failure_submissions|length > 0 %}

The following orders were NOT successfully submitted to Daklapack. @@ -168,6 +193,7 @@

Submit Daklapack Order

{% endfor %} +
{% endif %} {% if success_submissions|length > 0 %} diff --git a/microsetta_admin/tests/data/order_addresses_sample.xlsx b/microsetta_admin/tests/data/order_addresses_sample.xlsx index 005ac0a..902ecdc 100644 Binary files a/microsetta_admin/tests/data/order_addresses_sample.xlsx and b/microsetta_admin/tests/data/order_addresses_sample.xlsx differ diff --git a/microsetta_admin/tests/data/order_addresses_sample_hold.xlsx b/microsetta_admin/tests/data/order_addresses_sample_hold.xlsx new file mode 100644 index 0000000..23db5d0 Binary files /dev/null and b/microsetta_admin/tests/data/order_addresses_sample_hold.xlsx differ diff --git a/microsetta_admin/tests/test_routes.py b/microsetta_admin/tests/test_routes.py index 43fed19..6ad3ed4 100644 --- a/microsetta_admin/tests/test_routes.py +++ b/microsetta_admin/tests/test_routes.py @@ -474,8 +474,7 @@ def test_post_submit_daklapack_order_success(self): # server side issues one POST to the API api_post_1 = DummyResponse( 200, - {'order_submissions': - [ + {'order_submissions': [ {'order_id': '11211', 'order_address': {'address1': '123 Main St', 'address2': '', @@ -505,16 +504,52 @@ def test_post_submit_daklapack_order_success(self): 'phone': '(858) 555-1212', 'postalCode': 'KG7-448', 'state': 'Ontario'}, - 'order_success': False}]} + 'order_success': False}, + {'order_id': '11213', + 'order_address': {'address1': '38 Diagonal St', + 'address2': '', + 'city': 'Chiba', + 'companyName': 'Dan H', + 'country': 'Japan', + 'countryCode': 'jp', + 'firstName': 'Jerry', + 'insertion': '', + 'lastName': 'Index', + 'phone': '(858) 555-1212', + 'postalCode': '261-0022', + 'state': 'Chiba'}, + 'order_success': True}, + ]} ) self.mock_post.side_effect = [api_post_1] response = self._test_post_submit_daklapack_order() + self.assertNotIn(b'The following addresses are incomplete and NOT ' + b'submitted to Daklapack.', response.data) self.assertIn(b'The following orders were NOT successfully submitted ' b'to Daklapack.', response.data) self.assertIn(b'The following orders were successfully submitted ' b'to Daklapack', response.data) + # File: 3 complete addresses, 2 empty rows + # Expected: 3 addresses returned from Daklapack API + 2 table headers + self.assertEqual(response.data.count(b''), 5) + + def test_post_submit_daklapack_order_hold(self): + # No Private API Call + response = self._test_post_submit_daklapack_order( + "order_addresses_sample_hold.xlsx") + self.assertIn(b'The following addresses are incomplete and NOT ' + b'submitted to Daklapack.', response.data) + self.assertNotIn(b'The following orders were NOT successfully ' + b'submitted to Daklapack.', response.data) + self.assertNotIn(b'The following orders were successfully submitted ' + b'to Daklapack', response.data) + + # File: 4 complete addresses, 3 empty rows + # Expected: No API Call, 4 hold addresses + 1 table header + self.assertEqual(response.data.count(b''), 5) + def test_post_submit_daklapack_order_fail_api(self): # server side issues one POST to the API api_post_1 = DummyResponse(400, {