cc-py-commons 0.5.15__tar.gz → 0.5.35__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/PKG-INFO +1 -1
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/bids/bid_schema.py +13 -13
- cc_py_commons-0.5.35/cc_py_commons/carriers/account_carrier_map.py +12 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/carriers/account_carrier_map_schema.py +6 -7
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/carriers/carrier_schema.py +2 -2
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/config/env.py +5 -0
- cc_py_commons-0.5.35/cc_py_commons/config/web_socket_action.py +3 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/geolocate.py +36 -23
- cc_py_commons-0.5.35/cc_py_commons/loads/equipment_schema.py +16 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/loads/load.py +1 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/loads/load_schema.py +1 -0
- cc_py_commons-0.5.35/cc_py_commons/services/booking_agent/get_quote_by_load_id.py +19 -0
- cc_py_commons-0.5.35/cc_py_commons/services/booking_agent/list_bids.py +33 -0
- cc_py_commons-0.5.35/cc_py_commons/services/booking_agent/list_quotes.py +27 -0
- cc_py_commons-0.5.35/cc_py_commons/services/c4/get_account_settings.py +27 -0
- cc_py_commons-0.5.35/cc_py_commons/services/web_socket/send_notification.py +38 -0
- cc_py_commons-0.5.35/cc_py_commons/sqs/booking_assistant_cancel_quote_notification.py +31 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/sqs/booking_assistant_flow_event.py +3 -2
- cc_py_commons-0.5.35/cc_py_commons/sqs/sqs_service.py +86 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/tests/test_map_transaction.py +1 -0
- cc_py_commons-0.5.35/cc_py_commons/tests/test_web_socket_send_notification.py +39 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/transactions/map_transaction.py +1 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/transactions/transaction.py +1 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/transactions/transaction_schema.py +1 -0
- cc_py_commons-0.5.35/cc_py_commons/utils/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/bulk_lane_price_result_utils.py +3 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons.egg-info/PKG-INFO +1 -1
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons.egg-info/SOURCES.txt +8 -1
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/setup.py +1 -1
- cc_py_commons-0.5.15/cc_py_commons/carriers/account_carrier_map.py +0 -12
- cc_py_commons-0.5.15/cc_py_commons/loads/equipment_schema.py +0 -14
- cc_py_commons-0.5.15/cc_py_commons/services/c4/get_account_settings.py +0 -21
- cc_py_commons-0.5.15/cc_py_commons/services/mercury/get_lane_price_for_bulk.py +0 -23
- cc_py_commons-0.5.15/cc_py_commons/sqs/sqs_service.py +0 -25
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/README.md +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/bids/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/bids/bid.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/bids/bid_history.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/bids/bid_history_schema.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/carriers/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/carriers/carrier.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/carriers/contact.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/carriers/contact_schema.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/config/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/config/c4_account_settings.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/config/mcleod_load_fields.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/config/pc_miler_config.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/db/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/db/connection.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/lanes/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/lanes/carrier_lane.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/lanes/carrier_lane_schema.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/lanes/lane.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/lanes/lane_schema.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/loads/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/loads/equipment.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/loads/equipment_types.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/loads/freighthub_contact.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/loads/freighthub_contact_schema.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/loads/load_status.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/loads/location.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/loads/location_schema.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/loads/map_load_response.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/quotes/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/quotes/quote.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/quotes/quote_schema.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/quotes/quote_status.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/rfp/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/rfp/create_table.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/rfp/rfp_status.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/rfp/truck_lane_search_mapper.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/schemas/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/schemas/camel_case_schema.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/analytics/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/analytics/analytics_event.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/accept_bid.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/cancel_bid.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/constants.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/counter_bid.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/decline_bid.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/get_bid_by_amazon_order_id.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/get_quote.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/update_bid.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/amazon_session_token.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/constants.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/get_account.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/get_integration.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/get_users_for_account.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/refresh_amazon_token.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/carrier_hub/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/carrier_hub/get_carrier.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/carrier_hub/list_carriers.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/carrier_hub/list_contacts.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/carrier_hub/update_contact.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/freight_hub/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/freight_hub/post_freight_hub_load.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/create_account_folder.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/db/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/db/delete_table.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/get_client.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/get_green_screens_lane_price.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/get_import_stat.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/get_lane_price.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/list_clients.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/post_import_stat.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/update_import_stat.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/slack/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/services/slack/send_slack_message.py +0 -0
- {cc_py_commons-0.5.15/cc_py_commons/sns → cc_py_commons-0.5.35/cc_py_commons/services/web_socket}/__init__.py +0 -0
- {cc_py_commons-0.5.15/cc_py_commons/sns/booking_agent → cc_py_commons-0.5.35/cc_py_commons/sns}/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/sns/book_load_notification.py +0 -0
- {cc_py_commons-0.5.15/cc_py_commons/sqs → cc_py_commons-0.5.35/cc_py_commons/sns/booking_agent}/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/sns/booking_agent/bid_counter_failure_notification.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/sns/booking_agent/constants.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/sns/booking_agent/send_sns_notification.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/sns/booking_assistant_flow_notification.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/sns/import_movements_notification.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/sns/parsed_carrier_notification.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/sns/sns_service.py +0 -0
- {cc_py_commons-0.5.15/cc_py_commons/tests → cc_py_commons-0.5.35/cc_py_commons/sqs}/__init__.py +0 -0
- {cc_py_commons-0.5.15/cc_py_commons/transactions → cc_py_commons-0.5.35/cc_py_commons/tests}/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/tests/test_case_conversion.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/tests/test_lambda_utils.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/tests/test_temperature_utils.py +0 -0
- {cc_py_commons-0.5.15/cc_py_commons/utils → cc_py_commons-0.5.35/cc_py_commons/transactions}/__init__.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/transactions/equipment_clas_schema.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/transactions/equipment_class.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/transactions/equipment_mapping.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/transactions/equipment_mapping_schema.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/case_conversion.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/datadog_logger.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/datetimes.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/dimension_utils.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/geocode_location.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/get_delivery_date.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/json_logger.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/lambda_utils.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/local_file.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/logger.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/logger_v2.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/pc_miler_utils.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/price_utils.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/redis.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/s3_file.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/utils/temperature_utils.py +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons.egg-info/dependency_links.txt +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons.egg-info/requires.txt +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons.egg-info/top_level.txt +0 -0
- {cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/setup.cfg +0 -0
@@ -10,26 +10,26 @@ class BidSchema(CamelCaseSchema):
|
|
10
10
|
id = fields.UUID()
|
11
11
|
quote_id = fields.UUID()
|
12
12
|
carrier_id = fields.UUID()
|
13
|
-
receipt_id = fields.String(allow_none=True)
|
13
|
+
receipt_id = fields.String(allow_none=True, missing=None)
|
14
14
|
amount = fields.Integer()
|
15
|
-
estimated_days = fields.Integer()
|
16
|
-
notes = fields.String(allow_none=True)
|
15
|
+
estimated_days = fields.Integer(allow_none=True, missing=None)
|
16
|
+
notes = fields.String(allow_none=True, missing=None)
|
17
17
|
match_score = fields.Float(allow_none=True)
|
18
18
|
status_id = fields.UUID()
|
19
19
|
pickup_date = fields.Date()
|
20
20
|
delivery_date = fields.Date()
|
21
|
-
decline_reason = fields.String(allow_none=True)
|
21
|
+
decline_reason = fields.String(allow_none=True, missing=None)
|
22
22
|
bid_histories = fields.List(fields.Nested(BidHistorySchema), allow_none=True)
|
23
23
|
origin_deadhead = fields.Float(allow_none=True)
|
24
|
-
porus_truck_id = fields.UUID(allow_none=True)
|
25
|
-
truck_lane_id = fields.UUID(allow_none=True)
|
26
|
-
distance = fields.Float(allow_none=True)
|
27
|
-
origin_city = fields.String()
|
28
|
-
origin_state = fields.String()
|
29
|
-
origin_zip = fields.String(allow_none=True)
|
30
|
-
dest_city = fields.String()
|
31
|
-
dest_state = fields.String()
|
32
|
-
dest_zip = fields.String(allow_none=True)
|
24
|
+
porus_truck_id = fields.UUID(allow_none=True, missing=None)
|
25
|
+
truck_lane_id = fields.UUID(allow_none=True, missing=None)
|
26
|
+
distance = fields.Float(allow_none=True, missing=None)
|
27
|
+
origin_city = fields.String(missing=None)
|
28
|
+
origin_state = fields.String(missing=None)
|
29
|
+
origin_zip = fields.String(allow_none=True, missing=None)
|
30
|
+
dest_city = fields.String(missing=None)
|
31
|
+
dest_state = fields.String(missing=None)
|
32
|
+
dest_zip = fields.String(allow_none=True, missing=None)
|
33
33
|
invite_emailed_at = fields.DateTime(allow_none=True)
|
34
34
|
|
35
35
|
@post_load
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import datetime
|
2
|
+
import uuid
|
3
|
+
from dataclasses import dataclass, field
|
4
|
+
|
5
|
+
@dataclass
|
6
|
+
class AccountCarrierMap:
|
7
|
+
account_id: int
|
8
|
+
carrier_id: uuid.UUID
|
9
|
+
status: str
|
10
|
+
customer_code: str = field(default=None)
|
11
|
+
warmup_email_sent_at: datetime.date = field(default=None)
|
12
|
+
no_dispatch: bool = field(default=False)
|
{cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/carriers/account_carrier_map_schema.py
RENAMED
@@ -1,18 +1,17 @@
|
|
1
1
|
from marshmallow import fields, EXCLUDE, post_load
|
2
2
|
from cc_py_commons.schemas.camel_case_schema import CamelCaseSchema
|
3
|
-
from cc_py_commons.carriers.contact_schema import ContactSchema
|
4
3
|
from cc_py_commons.carriers.account_carrier_map import AccountCarrierMap
|
5
4
|
class AccountCarrierMapSchema(CamelCaseSchema):
|
6
5
|
class Meta:
|
7
6
|
unknown = EXCLUDE
|
8
7
|
|
9
8
|
account_id = fields.Integer()
|
10
|
-
customer_code = fields.String(allow_none=True)
|
11
9
|
carrier_id = fields.UUID()
|
12
|
-
status = fields.String(
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
status = fields.String()
|
11
|
+
customer_code = fields.String(allow_none=True, missing=None)
|
12
|
+
warmup_email_sent_at = fields.Date(allow_none=True, missing=None)
|
13
|
+
no_dispatch = fields.Boolean(allow_none=True, missing=None)
|
14
|
+
|
16
15
|
@post_load
|
17
|
-
def
|
16
|
+
def make_account_carrier_map(self, data, **kwargs):
|
18
17
|
return AccountCarrierMap(**data)
|
@@ -63,7 +63,7 @@ class CarrierSchema(CamelCaseSchema):
|
|
63
63
|
vetting_overall_display = fields.String(allow_none=True)
|
64
64
|
last_vetting_time = fields.Date(allow_none=True)
|
65
65
|
vetting_remarks = fields.String(allow_none=True)
|
66
|
-
|
66
|
+
|
67
67
|
@post_load
|
68
|
-
def
|
68
|
+
def make_carrier(self, data, **kwargs):
|
69
69
|
return Carrier(**data)
|
@@ -33,6 +33,8 @@ class Config(object):
|
|
33
33
|
BOOKING_ASSISTANT_SNS_TOPIC_ARN = 'arn:aws:sns:us-west-1:791608169866:booking-assistant-flow-test'
|
34
34
|
BOOKING_ASSISTANT_SNS_SUBJECT = 'booking-assistant-flow'
|
35
35
|
BOOKING_ASSISTANT_SNS_CLASS_NAME = 'com.cargochief.sdk.bookingagent.sns.BookingAssistantFlowNotification'
|
36
|
+
BOOKING_ASSISTANT_QUOTE_CANCEL_SUBJECT = 'quote-cancelled'
|
37
|
+
BOOKING_ASSISTANT_QUOTE_CANCEL_CLASS_NAME = 'com.cargochief.sdk.bookingagent.sns.QuoteCancelNotification'
|
36
38
|
IMPORT_MOVEMENTS_SNS_TOPIC_ARN = 'arn:aws:sns:us-west-1:791608169866:mcleod-import-movements-test'
|
37
39
|
IMPORT_MOVEMENTS_SNS_SUBJECT = 'import-movements'
|
38
40
|
IMPORT_MOVEMENTS_SNS_CLASS_NAME = 'com.cargochief.sdk.c4.sns.mcleod.ImportMovementsNotification'
|
@@ -58,6 +60,8 @@ class Config(object):
|
|
58
60
|
HERMES_SNS_ARN = 'arn:aws:sns:us-west-1:791608169866:hermes-sns-test'
|
59
61
|
C4_ACCOUNTS_BUCKET = 'c4-accounts-test'
|
60
62
|
ANALYTICS_SNS_ARN = 'arn:aws:sns:us-west-1:791608169866:analytics-test'
|
63
|
+
WEB_SOCKET_SNS_TOPIC_ARN = 'arn:aws:sns:us-west-1:791608169866:websocket-dev'
|
64
|
+
WEB_SOCKET_AUTH_TOKEN = os.getenv('WEB_SOCKET_AUTH_TOKEN')
|
61
65
|
|
62
66
|
# Database
|
63
67
|
DB_USERNAME = os.getenv('DB_USERNAME')
|
@@ -117,6 +121,7 @@ class ProductionConfig(Config):
|
|
117
121
|
HERMES_SNS_ARN = 'arn:aws:sns:us-west-1:791608169866:hermes-sns-prod'
|
118
122
|
C4_ACCOUNTS_BUCKET = 'c4-accounts-prod'
|
119
123
|
ANALYTICS_SNS_ARN ='arn:aws:sns:us-west-1:791608169866:analytics-prod'
|
124
|
+
WEB_SOCKET_SNS_TOPIC_ARN = 'arn:aws:sns:us-west-1:791608169866:websocket-prod'
|
120
125
|
|
121
126
|
config_options = {
|
122
127
|
'local': LocalConfig,
|
@@ -75,29 +75,34 @@ def get_location_with_country(city, state, zipcode, country, logger, reset_cache
|
|
75
75
|
|
76
76
|
return data
|
77
77
|
|
78
|
-
def get_distance(origin_latitude, origin_longitude, destination_latitude, destination_longitude, logger):
|
78
|
+
def get_distance(origin_latitude, origin_longitude, destination_latitude, destination_longitude, logger, with_duration=False):
|
79
79
|
if not origin_latitude or not origin_longitude or \
|
80
80
|
not destination_latitude or not destination_longitude:
|
81
81
|
raise Exception("Calculating distance requires both origin and destination lat/lng")
|
82
82
|
|
83
83
|
from_cache = False
|
84
|
-
pc_miler_can_be_called = False
|
85
84
|
distance_cache_key = __get_distance_cache_key(origin_latitude, origin_longitude, destination_latitude, destination_longitude)
|
86
|
-
|
85
|
+
distance_data_dict = __get_distance_from_cache(distance_cache_key, logger)
|
87
86
|
|
88
|
-
if
|
87
|
+
if distance_data_dict:
|
89
88
|
from_cache = True
|
90
89
|
|
91
|
-
|
92
|
-
|
90
|
+
missing_duration_and_is_required = (with_duration and not distance_data_dict.get('duration'))
|
91
|
+
if not distance_data_dict or missing_duration_and_is_required:
|
92
|
+
distance_data_dict = __get_google_distance(origin_latitude, origin_longitude, destination_latitude, destination_longitude, logger)
|
93
93
|
|
94
|
-
if
|
95
|
-
if not from_cache:
|
96
|
-
__cache_distance(distance_cache_key,
|
94
|
+
if distance_data_dict:
|
95
|
+
if not from_cache or missing_duration_and_is_required:
|
96
|
+
__cache_distance(distance_cache_key, distance_data_dict, logger)
|
97
97
|
else:
|
98
98
|
logger.debug(f"geolocate.get_distance - Google returned no result for {distance_cache_key}")
|
99
99
|
|
100
|
-
|
100
|
+
if distance_data_dict:
|
101
|
+
if with_duration:
|
102
|
+
return distance_data_dict
|
103
|
+
else:
|
104
|
+
return distance_data_dict.get('distance')
|
105
|
+
return None
|
101
106
|
|
102
107
|
def get_timezone(lat,lng, logger):
|
103
108
|
from_cache = False
|
@@ -124,7 +129,7 @@ def get_timezone(lat,lng, logger):
|
|
124
129
|
return timezone
|
125
130
|
|
126
131
|
def __get_google_distance(origin_latitude, origin_longitude, destination_latitude, destination_longitude, logger):
|
127
|
-
|
132
|
+
distance_data = None
|
128
133
|
try:
|
129
134
|
gmaps = googlemaps.Client(key=app_config.GOOGLE_API_KEY)
|
130
135
|
origins = [f'{origin_latitude} {origin_longitude}']
|
@@ -137,10 +142,16 @@ def __get_google_distance(origin_latitude, origin_longitude, destination_latitud
|
|
137
142
|
if response and response['rows'][0]['elements'][0].get('distance', None):
|
138
143
|
distance_in_meters = response['rows'][0]['elements'][0]['distance']['value']
|
139
144
|
distance = distance_in_meters / 1609
|
145
|
+
duration_seconds = response['rows'][0]['elements'][0]['duration']['value']
|
146
|
+
duration_minutes = duration_seconds / 60
|
147
|
+
distance_data = {
|
148
|
+
'distance': distance,
|
149
|
+
'duration': duration_minutes
|
150
|
+
}
|
140
151
|
except Exception as e:
|
141
152
|
logger.error("geolocate.__get_google_distance: Error while getting distance from google", e)
|
142
|
-
|
143
|
-
return
|
153
|
+
distance_data = None
|
154
|
+
return distance_data
|
144
155
|
|
145
156
|
def __get_google_location(city, state, zipcode, country, logger):
|
146
157
|
try:
|
@@ -185,8 +196,7 @@ def __get_google_location(city, state, zipcode, country, logger):
|
|
185
196
|
logger.warning(f"Cannot select a single address from multiple for {loc_str}.")
|
186
197
|
return None
|
187
198
|
response = [selected_address]
|
188
|
-
|
189
|
-
return data
|
199
|
+
return __parse_response(response, city)
|
190
200
|
except googlemaps.exceptions.Timeout as e:
|
191
201
|
msg = "geolocate.__get_google_location - Location lookup timed out {0}, {1}, {2}: {3}".format(city, state, zipcode, e)
|
192
202
|
|
@@ -351,19 +361,22 @@ def __get_location_string(city, state, zipcode):
|
|
351
361
|
|
352
362
|
return location_string.lower()
|
353
363
|
|
354
|
-
def __cache_distance(distance_cache_key,
|
355
|
-
distance_db_conn.set(distance_cache_key,
|
364
|
+
def __cache_distance(distance_cache_key, distance_data, logger):
|
365
|
+
distance_db_conn.set(distance_cache_key, str(distance_data))
|
356
366
|
|
357
367
|
def __get_distance_from_cache(distance_cache_key, logger):
|
358
|
-
|
368
|
+
distance_data = {}
|
359
369
|
try:
|
360
|
-
|
361
|
-
if
|
362
|
-
|
370
|
+
cached_data = distance_db_conn.get(distance_cache_key)
|
371
|
+
if cached_data:
|
372
|
+
if 'duration' in str(cached_data):
|
373
|
+
distance_data = literal_eval(cached_data.decode('utf-8'))
|
374
|
+
else:
|
375
|
+
distance_data['distance'] = float(cached_data)
|
363
376
|
except Exception as e:
|
364
377
|
logger.warn("geolocate.__get_distance_from_cache: Error while getting distance from cache", e)
|
365
|
-
|
366
|
-
return
|
378
|
+
distance_data = {}
|
379
|
+
return distance_data
|
367
380
|
|
368
381
|
def __get_distance_cache_key(origin_latitude, origin_longitude, destination_latitude, destination_longitude):
|
369
382
|
return f'{__truncate(origin_latitude)},{__truncate(origin_longitude)}->{__truncate(destination_latitude)},{__truncate(destination_longitude)}'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
from marshmallow import fields, EXCLUDE, post_load
|
2
|
+
from cc_py_commons.schemas.camel_case_schema import CamelCaseSchema
|
3
|
+
from cc_py_commons.loads.equipment import Equipment
|
4
|
+
|
5
|
+
class EquipmentSchema(CamelCaseSchema):
|
6
|
+
class Meta:
|
7
|
+
unknown = EXCLUDE
|
8
|
+
|
9
|
+
id = fields.UUID()
|
10
|
+
name = fields.String()
|
11
|
+
active = fields.Boolean(default=True) # Match the dataclass default
|
12
|
+
|
13
|
+
@post_load
|
14
|
+
def make_equipment(self, data, **kwargs):
|
15
|
+
return Equipment(**data)
|
16
|
+
|
@@ -76,6 +76,7 @@ class LoadSchema(CamelCaseSchema):
|
|
76
76
|
ltl = fields.Boolean(allow_none=True, default=False, missing=False)
|
77
77
|
special_instructions = fields.String(allow_none=True)
|
78
78
|
request_id = fields.UUID(allow_none=True)
|
79
|
+
predicted_price: int = fields.Integer(allow_none=True)
|
79
80
|
|
80
81
|
@post_load
|
81
82
|
def make_load(self, data, **kwargs):
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import requests
|
2
|
+
|
3
|
+
from cc_py_commons.utils import json_logger
|
4
|
+
from .constants import BOOKING_AGENT_TOKEN, BOOKING_AGENT_URL
|
5
|
+
|
6
|
+
|
7
|
+
def execute(load_id):
|
8
|
+
url = f"{BOOKING_AGENT_URL}/quote/by/loadId/{load_id}"
|
9
|
+
booking_agent_headers = {
|
10
|
+
"Authorization": f"Bearer {BOOKING_AGENT_TOKEN}",
|
11
|
+
"Content-Type": "application/json"
|
12
|
+
}
|
13
|
+
response = requests.get(url, headers=booking_agent_headers)
|
14
|
+
if response.status_code == 200:
|
15
|
+
return response.json()
|
16
|
+
else:
|
17
|
+
json_logger.warning(None, 'Failed to get quote from Booking Agent',
|
18
|
+
status_code=response.status_code, load_id=str(load_id))
|
19
|
+
return None
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
import requests
|
4
|
+
from dateutil.parser import parse
|
5
|
+
|
6
|
+
from cc_py_commons.bids.bid_schema import BidSchema
|
7
|
+
from cc_py_commons.utils import json_logger
|
8
|
+
|
9
|
+
BOOKING_AGENT_URL = os.environ.get('BOOKING_AGENT_URL')
|
10
|
+
BOOKING_AGENT_TOKEN = os.environ.get("BOOKING_AGENT_TOKEN")
|
11
|
+
|
12
|
+
|
13
|
+
def execute(account_id, filters_dict):
|
14
|
+
url = f"{BOOKING_AGENT_URL}/bid/match"
|
15
|
+
token = f"Bearer {BOOKING_AGENT_TOKEN}"
|
16
|
+
headers = {
|
17
|
+
"Authorization": token
|
18
|
+
}
|
19
|
+
json_logger.debug(account_id, f"Requesting bids from booking-agent", url=url, filters=filters_dict)
|
20
|
+
response = requests.get(url, headers=headers, params=filters_dict)
|
21
|
+
bids = []
|
22
|
+
if response.status_code == 200:
|
23
|
+
bids = response.json()['content']
|
24
|
+
for bid in bids:
|
25
|
+
bid['pickupDate'] = parse(bid['pickupDate']).strftime('%Y-%m-%d')
|
26
|
+
bid['deliveryDate'] = parse(bid['deliveryDate']).strftime('%Y-%m-%d')
|
27
|
+
if bid.get('inviteEmailedAt'):
|
28
|
+
bid['inviteEmailedAt'] = parse(bid['inviteEmailedAt']).isoformat()
|
29
|
+
for bid_history in bid.get('bidHistories', []):
|
30
|
+
bid_history['pickupDate'] = parse(bid_history['pickupDate']).strftime('%Y-%m-%d')
|
31
|
+
bid_history['deliveryDate'] = parse(bid_history['deliveryDate']).strftime('%Y-%m-%d')
|
32
|
+
bids = BidSchema().load(bids, many=True)
|
33
|
+
return bids
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import requests
|
2
|
+
import os
|
3
|
+
from dateutil.parser import parse
|
4
|
+
|
5
|
+
from cc_py_commons.utils import json_logger
|
6
|
+
from cc_py_commons.quotes.quote_schema import QuoteSchema
|
7
|
+
|
8
|
+
BOOKING_AGENT_URL = os.environ.get('BOOKING_AGENT_URL')
|
9
|
+
BOOKING_AGENT_TOKEN = os.environ.get("BOOKING_AGENT_TOKEN")
|
10
|
+
|
11
|
+
|
12
|
+
def execute(account_id, filters_dict):
|
13
|
+
url = f"{BOOKING_AGENT_URL}/quote"
|
14
|
+
token = f"Bearer {BOOKING_AGENT_TOKEN}"
|
15
|
+
headers = {
|
16
|
+
"Authorization": token
|
17
|
+
}
|
18
|
+
json_logger.debug(account_id, f"Requesting quotes from booking-agent", url=url, filters=filters_dict)
|
19
|
+
response = requests.get(url, headers=headers, params=filters_dict)
|
20
|
+
quotes = []
|
21
|
+
if response.status_code == 200:
|
22
|
+
quotes = response.json()['content']
|
23
|
+
for quote in quotes:
|
24
|
+
quote['pickupDate'] = parse(quote['pickupDate']).strftime('%Y-%m-%d')
|
25
|
+
quote['deliveryDate'] = parse(quote['deliveryDate']).strftime('%Y-%m-%d')
|
26
|
+
quotes = QuoteSchema().load(quotes, many=True)
|
27
|
+
return quotes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import requests
|
2
|
+
|
3
|
+
from cc_py_commons.utils import json_logger
|
4
|
+
from .constants import C4_API_AUTH_TOKEN, C4_API_URL
|
5
|
+
from . import get_account
|
6
|
+
|
7
|
+
|
8
|
+
def by_user_id(user_id):
|
9
|
+
url = f"{C4_API_URL}/user/{user_id}/accountSettings"
|
10
|
+
token = f"Bearer {C4_API_AUTH_TOKEN}"
|
11
|
+
headers = {
|
12
|
+
"Authorization": token
|
13
|
+
}
|
14
|
+
json_logger.debug(None, 'Getting account settings', url=url, headers=headers)
|
15
|
+
response = requests.get(url, headers=headers)
|
16
|
+
if response.status_code != 200:
|
17
|
+
json_logger.warning(None, 'Request to get account settings failed', status_code=response.status_code)
|
18
|
+
return None
|
19
|
+
return response.json().get('data')
|
20
|
+
|
21
|
+
|
22
|
+
def by_account_id(account_id):
|
23
|
+
account = get_account.execute(account_id)
|
24
|
+
if account:
|
25
|
+
return account.get('accountSettings')
|
26
|
+
else:
|
27
|
+
return None
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import json
|
2
|
+
import traceback
|
3
|
+
|
4
|
+
from cc_py_commons.config.env import app_config
|
5
|
+
from cc_py_commons.config.web_socket_action import WebSocketAction
|
6
|
+
from cc_py_commons.sns.sns_service import SnsService
|
7
|
+
from cc_py_commons.utils import json_logger
|
8
|
+
|
9
|
+
|
10
|
+
def execute(action, user_id, account_id, payload):
|
11
|
+
if not action or not account_id or not payload:
|
12
|
+
json_logger.warning(account_id, 'Missing required parameters')
|
13
|
+
return None
|
14
|
+
valid_actions = [WebSocketAction.BROADCAST_TO_USER, WebSocketAction.BROADCAST_TO_ACCOUNT]
|
15
|
+
if action not in valid_actions:
|
16
|
+
json_logger.warning(account_id, f'Invalid action. Should be one of {valid_actions}')
|
17
|
+
return None
|
18
|
+
web_socket_auth_token = app_config.WEB_SOCKET_AUTH_TOKEN
|
19
|
+
if not web_socket_auth_token:
|
20
|
+
json_logger.warning(account_id, 'Missing WEB_SOCKET_AUTH_TOKEN')
|
21
|
+
return None
|
22
|
+
try:
|
23
|
+
message = {
|
24
|
+
'authKey': web_socket_auth_token,
|
25
|
+
'action': action,
|
26
|
+
'userId': user_id,
|
27
|
+
'accountId': account_id,
|
28
|
+
'payload': payload
|
29
|
+
}
|
30
|
+
sns_service = SnsService()
|
31
|
+
sns_service.send(app_config.WEB_SOCKET_SNS_TOPIC_ARN, 'web-socket-message', json.dumps(message))
|
32
|
+
successful_message = 'Successfully sent the notification'
|
33
|
+
json_logger.info(account_id, successful_message)
|
34
|
+
return successful_message
|
35
|
+
except Exception as e:
|
36
|
+
json_logger.error(account_id, 'Failed to send web socket notification', error=str(e),
|
37
|
+
stacktrace=traceback.format_exc())
|
38
|
+
return None
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import json
|
2
|
+
import traceback
|
3
|
+
|
4
|
+
from cc_py_commons.config.env import app_config
|
5
|
+
from cc_py_commons.sqs.sqs_service import SqsService
|
6
|
+
from cc_py_commons.utils.logger_v2 import logger
|
7
|
+
|
8
|
+
class BookingAssistantQuoteCancelNotification:
|
9
|
+
|
10
|
+
def send(self, load_id):
|
11
|
+
'''
|
12
|
+
Sends and event to the Booking Assistant Flow SQS queue specified in the config.
|
13
|
+
Returns the messageId of the enqueued message for later retrieval.
|
14
|
+
'''
|
15
|
+
event = {
|
16
|
+
'loadId': str(load_id),
|
17
|
+
'subject': app_config.BOOKING_ASSISTANT_QUOTE_CANCEL_SUBJECT,
|
18
|
+
'className': app_config.BOOKING_ASSISTANT_QUOTE_CANCEL_CLASS_NAME
|
19
|
+
}
|
20
|
+
logger.debug(f"sending event {event} to {app_config.BOOKING_ASSISTANT_FLOW_QUEUE}")
|
21
|
+
|
22
|
+
try:
|
23
|
+
sqs_service = SqsService()
|
24
|
+
return sqs_service.send(app_config.BOOKING_ASSISTANT_FLOW_QUEUE, json.dumps(event), app_config.BOOKING_ASSISTANT_DELAY_SECONDS)
|
25
|
+
except Exception as e:
|
26
|
+
logger.error(json.dumps({
|
27
|
+
'message': 'Failed to send class BookingAssistantQuoteCancelNotification',
|
28
|
+
'error': str(e),
|
29
|
+
'sta_cktrace': traceback.format_exc(),
|
30
|
+
'event': event
|
31
|
+
}))
|
{cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/sqs/booking_assistant_flow_event.py
RENAMED
@@ -6,7 +6,7 @@ from cc_py_commons.utils.logger_v2 import logger
|
|
6
6
|
|
7
7
|
class BookingAssistantFlowEvent:
|
8
8
|
|
9
|
-
def send(self, user_id, load, params, capacity_search_equipments, request_id):
|
9
|
+
def send(self, user_id, load, params, capacity_search_equipments, request_id, auto_invite_details=None):
|
10
10
|
'''
|
11
11
|
Sends and event to the Booking Assistant Flow SQS queue specified in the config.
|
12
12
|
Returns the messageId of the enqueued message for later retrieval.
|
@@ -18,7 +18,8 @@ class BookingAssistantFlowEvent:
|
|
18
18
|
'capacitySearchEquipments': capacity_search_equipments,
|
19
19
|
'requestId': request_id,
|
20
20
|
'subject': f'{app_config.BOOKING_ASSISTANT_SNS_SUBJECT}',
|
21
|
-
'className': f'{app_config.BOOKING_ASSISTANT_SNS_CLASS_NAME}'
|
21
|
+
'className': f'{app_config.BOOKING_ASSISTANT_SNS_CLASS_NAME}',
|
22
|
+
'autoInviteDetails': auto_invite_details
|
22
23
|
}
|
23
24
|
logger.debug(f"sending event {event} to {app_config.BOOKING_ASSISTANT_FLOW_QUEUE}")
|
24
25
|
|
@@ -0,0 +1,86 @@
|
|
1
|
+
import json
|
2
|
+
from uuid import uuid4
|
3
|
+
import boto3
|
4
|
+
|
5
|
+
class SqsService:
|
6
|
+
def send(self, queue_url, message, delaySeconds=0, messageGroupId=None):
|
7
|
+
'''
|
8
|
+
Sends a message to the specified queue and returns the messageId.
|
9
|
+
The messageId can be used to lookup and delete the message in the queue.
|
10
|
+
'''
|
11
|
+
sqs = boto3.client('sqs')
|
12
|
+
if messageGroupId:
|
13
|
+
response = sqs.send_message(
|
14
|
+
QueueUrl=queue_url,
|
15
|
+
MessageBody=message,
|
16
|
+
DelaySeconds=delaySeconds,
|
17
|
+
MessageAttributes={},
|
18
|
+
MessageGroupId=messageGroupId
|
19
|
+
)
|
20
|
+
else:
|
21
|
+
response = sqs.send_message(
|
22
|
+
QueueUrl=queue_url,
|
23
|
+
MessageBody=message,
|
24
|
+
DelaySeconds=delaySeconds,
|
25
|
+
MessageAttributes={}
|
26
|
+
)
|
27
|
+
return response.get('MessageId')
|
28
|
+
|
29
|
+
def send_batches(self, queue_url, messages):
|
30
|
+
'''
|
31
|
+
Sends all messages to the specified queue in groups of 10 (the limit of send_batch)
|
32
|
+
The messageId can be used to lookup and delete the message in the queue.
|
33
|
+
Args:
|
34
|
+
queue_url (str): The URL of the Amazon SQS queue
|
35
|
+
messages (list): List of messages to be sent
|
36
|
+
|
37
|
+
Returns:
|
38
|
+
dict: Results containing 'successful' and 'failed' message lists
|
39
|
+
'''
|
40
|
+
results = {
|
41
|
+
'successful': [],
|
42
|
+
'failed': []
|
43
|
+
}
|
44
|
+
|
45
|
+
if not messages:
|
46
|
+
return results
|
47
|
+
|
48
|
+
sqs = boto3.client('sqs')
|
49
|
+
entries = [
|
50
|
+
{
|
51
|
+
# each message must have a unique id
|
52
|
+
'Id': str(uuid4()),
|
53
|
+
'MessageBody': json.dumps(message),
|
54
|
+
}
|
55
|
+
for message in messages
|
56
|
+
]
|
57
|
+
|
58
|
+
# SQS can only process 10 messages per batch
|
59
|
+
batch_size = 10
|
60
|
+
|
61
|
+
# Split messages into batches of 10
|
62
|
+
for i in range(0, len(entries), batch_size):
|
63
|
+
batch = entries[i:i + batch_size]
|
64
|
+
|
65
|
+
try:
|
66
|
+
response = sqs.send_message_batch(
|
67
|
+
QueueUrl=queue_url,
|
68
|
+
Entries=batch
|
69
|
+
)
|
70
|
+
|
71
|
+
# Track successful and failed messages
|
72
|
+
if 'Successful' in response:
|
73
|
+
results['successful'].extend(response['Successful'])
|
74
|
+
if 'Failed' in response:
|
75
|
+
results['failed'].extend(response['Failed'])
|
76
|
+
|
77
|
+
except Exception as e:
|
78
|
+
# Mark all messages in failed batch
|
79
|
+
failed_batch = [{
|
80
|
+
'Id': entry['Id'],
|
81
|
+
'Error': str(e),
|
82
|
+
'Message': entry['MessageBody']
|
83
|
+
} for entry in batch]
|
84
|
+
results['failed'].extend(failed_batch)
|
85
|
+
|
86
|
+
return results
|
@@ -61,3 +61,4 @@ class TestMapTransaction(unittest.TestCase):
|
|
61
61
|
t = from_load(self.valid_load)
|
62
62
|
self.assertEqual(self.valid_load.reference_number, t.reference_number)
|
63
63
|
self.assertEqual(self.valid_load.request_id, t.request_id)
|
64
|
+
self.assertEqual(self.valid_load.customer_id, t.user_id)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
from unittest import TestCase
|
2
|
+
from unittest.mock import patch
|
3
|
+
|
4
|
+
from cc_py_commons.config.web_socket_action import WebSocketAction
|
5
|
+
from cc_py_commons.services.web_socket import send_notification
|
6
|
+
from cc_py_commons.sns.sns_service import SnsService
|
7
|
+
|
8
|
+
|
9
|
+
@patch.object(SnsService, 'send')
|
10
|
+
class TestSendNotification(TestCase):
|
11
|
+
|
12
|
+
def test_when_required_parameters_are_missing(self, sns_service_send):
|
13
|
+
result = send_notification.execute(WebSocketAction.BROADCAST_TO_ACCOUNT,
|
14
|
+
None, None, {'message': 'test'})
|
15
|
+
|
16
|
+
self.assertIsNone(result)
|
17
|
+
sns_service_send.assert_not_called()
|
18
|
+
|
19
|
+
def test_invalid_action(self, sns_service_send):
|
20
|
+
result = send_notification.execute('INVALID_ACTION',
|
21
|
+
None, 1234, {'message': 'test'})
|
22
|
+
|
23
|
+
self.assertIsNone(result)
|
24
|
+
sns_service_send.assert_not_called()
|
25
|
+
|
26
|
+
def test_when_web_socket_token_is_missing(self, sns_service_send):
|
27
|
+
result = send_notification.execute(WebSocketAction.BROADCAST_TO_ACCOUNT,
|
28
|
+
None, 1234, {'message': 'test'})
|
29
|
+
|
30
|
+
self.assertIsNone(result)
|
31
|
+
sns_service_send.assert_not_called()
|
32
|
+
|
33
|
+
@patch('cc_py_commons.config.env.app_config.WEB_SOCKET_AUTH_TOKEN', 'TOKEN')
|
34
|
+
def test_valid_request(self, sns_service_send):
|
35
|
+
result = send_notification.execute(WebSocketAction.BROADCAST_TO_ACCOUNT,
|
36
|
+
None, 1234, {'message': 'test'})
|
37
|
+
|
38
|
+
self.assertIsNotNone(result)
|
39
|
+
sns_service_send.assert_called_once()
|
@@ -60,6 +60,7 @@ def from_load(load):
|
|
60
60
|
trans_data['pickup_close_time'] = load.pickup_close_time
|
61
61
|
trans_data['freight_hub_load_id'] = load.id
|
62
62
|
trans_data['revenue_code'] = load.revenue_code
|
63
|
+
trans_data['user_id'] = load.customer_id
|
63
64
|
if load.special_instructions:
|
64
65
|
trans_data['comments'] = load.special_instructions
|
65
66
|
if load.linear_feet:
|
{cc_py_commons-0.5.15 → cc_py_commons-0.5.35}/cc_py_commons/transactions/transaction_schema.py
RENAMED
@@ -106,6 +106,7 @@ class TransactionSchema(CamelCaseSchema):
|
|
106
106
|
revenue_code = fields.String(allow_none=True)
|
107
107
|
request_id = fields.UUID(allow_none=True)
|
108
108
|
mcleod_movement_id = fields.String(allow_none=True)
|
109
|
+
user_id = fields.Integer(allow_none=True)
|
109
110
|
|
110
111
|
@post_load
|
111
112
|
def classify(self, data, **kwargs):
|
File without changes
|