cc-py-commons 0.5.13__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.13 → cc_py_commons-0.5.35}/PKG-INFO +1 -1
- {cc_py_commons-0.5.13 → 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.13 → cc_py_commons-0.5.35}/cc_py_commons/carriers/account_carrier_map_schema.py +6 -7
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/carriers/carrier_schema.py +2 -2
- {cc_py_commons-0.5.13 → 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.13 → cc_py_commons-0.5.35}/cc_py_commons/geolocate.py +191 -154
- cc_py_commons-0.5.35/cc_py_commons/loads/equipment_schema.py +16 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/loads/load.py +1 -0
- {cc_py_commons-0.5.13 → 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.13 → 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.13 → 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.13 → cc_py_commons-0.5.35}/cc_py_commons/transactions/map_transaction.py +1 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/transactions/transaction.py +1 -0
- {cc_py_commons-0.5.13 → 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.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/bulk_lane_price_result_utils.py +3 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons.egg-info/PKG-INFO +1 -1
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons.egg-info/SOURCES.txt +8 -1
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/setup.py +1 -1
- cc_py_commons-0.5.13/cc_py_commons/carriers/account_carrier_map.py +0 -12
- cc_py_commons-0.5.13/cc_py_commons/loads/equipment_schema.py +0 -14
- cc_py_commons-0.5.13/cc_py_commons/services/c4/get_account_settings.py +0 -21
- cc_py_commons-0.5.13/cc_py_commons/services/mercury/get_lane_price_for_bulk.py +0 -23
- cc_py_commons-0.5.13/cc_py_commons/sqs/sqs_service.py +0 -25
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/README.md +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/bids/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/bids/bid.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/bids/bid_history.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/bids/bid_history_schema.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/carriers/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/carriers/carrier.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/carriers/contact.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/carriers/contact_schema.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/config/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/config/c4_account_settings.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/config/mcleod_load_fields.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/config/pc_miler_config.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/db/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/db/connection.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/lanes/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/lanes/carrier_lane.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/lanes/carrier_lane_schema.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/lanes/lane.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/lanes/lane_schema.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/loads/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/loads/equipment.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/loads/equipment_types.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/loads/freighthub_contact.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/loads/freighthub_contact_schema.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/loads/load_status.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/loads/location.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/loads/location_schema.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/loads/map_load_response.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/quotes/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/quotes/quote.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/quotes/quote_schema.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/quotes/quote_status.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/rfp/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/rfp/create_table.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/rfp/rfp_status.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/rfp/truck_lane_search_mapper.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/schemas/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/schemas/camel_case_schema.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/analytics/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/analytics/analytics_event.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/accept_bid.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/cancel_bid.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/constants.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/counter_bid.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/decline_bid.py +0 -0
- {cc_py_commons-0.5.13 → 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.13 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/get_quote.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/booking_agent/update_bid.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/amazon_session_token.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/constants.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/get_account.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/get_integration.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/get_users_for_account.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/c4/refresh_amazon_token.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/carrier_hub/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/carrier_hub/get_carrier.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/carrier_hub/list_carriers.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/carrier_hub/list_contacts.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/carrier_hub/update_contact.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/freight_hub/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/freight_hub/post_freight_hub_load.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/create_account_folder.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/db/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/db/delete_table.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/get_client.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/get_green_screens_lane_price.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/get_import_stat.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/get_lane_price.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/list_clients.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/post_import_stat.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/mercury/update_import_stat.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/slack/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/services/slack/send_slack_message.py +0 -0
- {cc_py_commons-0.5.13/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.13/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.13 → cc_py_commons-0.5.35}/cc_py_commons/sns/book_load_notification.py +0 -0
- {cc_py_commons-0.5.13/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.13 → cc_py_commons-0.5.35}/cc_py_commons/sns/booking_agent/bid_counter_failure_notification.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/sns/booking_agent/constants.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/sns/booking_agent/send_sns_notification.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/sns/booking_assistant_flow_notification.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/sns/import_movements_notification.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/sns/parsed_carrier_notification.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/sns/sns_service.py +0 -0
- {cc_py_commons-0.5.13/cc_py_commons/tests → cc_py_commons-0.5.35/cc_py_commons/sqs}/__init__.py +0 -0
- {cc_py_commons-0.5.13/cc_py_commons/transactions → cc_py_commons-0.5.35/cc_py_commons/tests}/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/tests/test_case_conversion.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/tests/test_lambda_utils.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/tests/test_temperature_utils.py +0 -0
- {cc_py_commons-0.5.13/cc_py_commons/utils → cc_py_commons-0.5.35/cc_py_commons/transactions}/__init__.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/transactions/equipment_clas_schema.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/transactions/equipment_class.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/transactions/equipment_mapping.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/transactions/equipment_mapping_schema.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/case_conversion.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/datadog_logger.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/datetimes.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/dimension_utils.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/geocode_location.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/get_delivery_date.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/json_logger.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/lambda_utils.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/local_file.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/logger.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/logger_v2.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/pc_miler_utils.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/price_utils.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/redis.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/s3_file.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons/utils/temperature_utils.py +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons.egg-info/dependency_links.txt +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons.egg-info/requires.txt +0 -0
- {cc_py_commons-0.5.13 → cc_py_commons-0.5.35}/cc_py_commons.egg-info/top_level.txt +0 -0
- {cc_py_commons-0.5.13 → 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.13 → 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,
|
@@ -25,7 +25,7 @@ def get_location_with_country(city, state, zipcode, country, logger, reset_cache
|
|
25
25
|
from_cache = True
|
26
26
|
else:
|
27
27
|
logger.debug(json.dumps({
|
28
|
-
'message': 'Found
|
28
|
+
'message': 'Found location in cache that was not a match',
|
29
29
|
'city': city,
|
30
30
|
'state': state,
|
31
31
|
'zipcode': zipcode,
|
@@ -50,6 +50,23 @@ def get_location_with_country(city, state, zipcode, country, logger, reset_cache
|
|
50
50
|
from_cache = False
|
51
51
|
data = __get_google_location(city=None, state=None, zipcode=postcode, country=None, logger=logger)
|
52
52
|
|
53
|
+
if data and not data.get('postcode'):
|
54
|
+
matching_location = __get_matching_location_from_cache(city, state, data.get('lat'), data.get('lng'), logger)
|
55
|
+
if matching_location:
|
56
|
+
data['postcode'] = matching_location.get('postcode')
|
57
|
+
else:
|
58
|
+
gmaps = googlemaps.Client(key=app_config.GOOGLE_API_KEY)
|
59
|
+
response = None
|
60
|
+
if zipcode:
|
61
|
+
response = gmaps.geocode(zipcode)
|
62
|
+
elif data.get('lat') and data.get('lng'):
|
63
|
+
response = gmaps.reverse_geocode((data.get('lat'), data.get('lng')))
|
64
|
+
post_code_data = __parse_response(response, city)
|
65
|
+
data['postcode'] = post_code_data['postcode'] if post_code_data else None
|
66
|
+
|
67
|
+
if data.get('postcode'):
|
68
|
+
__cache_location(city, state, zipcode, data, logger)
|
69
|
+
|
53
70
|
if data:
|
54
71
|
if not from_cache:
|
55
72
|
__cache_location(city, state, zipcode, data, logger)
|
@@ -58,29 +75,34 @@ def get_location_with_country(city, state, zipcode, country, logger, reset_cache
|
|
58
75
|
|
59
76
|
return data
|
60
77
|
|
61
|
-
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):
|
62
79
|
if not origin_latitude or not origin_longitude or \
|
63
80
|
not destination_latitude or not destination_longitude:
|
64
81
|
raise Exception("Calculating distance requires both origin and destination lat/lng")
|
65
82
|
|
66
83
|
from_cache = False
|
67
|
-
pc_miler_can_be_called = False
|
68
84
|
distance_cache_key = __get_distance_cache_key(origin_latitude, origin_longitude, destination_latitude, destination_longitude)
|
69
|
-
|
85
|
+
distance_data_dict = __get_distance_from_cache(distance_cache_key, logger)
|
70
86
|
|
71
|
-
if
|
87
|
+
if distance_data_dict:
|
72
88
|
from_cache = True
|
73
89
|
|
74
|
-
|
75
|
-
|
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)
|
76
93
|
|
77
|
-
if
|
78
|
-
if not from_cache:
|
79
|
-
__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)
|
80
97
|
else:
|
81
98
|
logger.debug(f"geolocate.get_distance - Google returned no result for {distance_cache_key}")
|
82
99
|
|
83
|
-
|
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
|
84
106
|
|
85
107
|
def get_timezone(lat,lng, logger):
|
86
108
|
from_cache = False
|
@@ -107,7 +129,7 @@ def get_timezone(lat,lng, logger):
|
|
107
129
|
return timezone
|
108
130
|
|
109
131
|
def __get_google_distance(origin_latitude, origin_longitude, destination_latitude, destination_longitude, logger):
|
110
|
-
|
132
|
+
distance_data = None
|
111
133
|
try:
|
112
134
|
gmaps = googlemaps.Client(key=app_config.GOOGLE_API_KEY)
|
113
135
|
origins = [f'{origin_latitude} {origin_longitude}']
|
@@ -120,14 +142,23 @@ def __get_google_distance(origin_latitude, origin_longitude, destination_latitud
|
|
120
142
|
if response and response['rows'][0]['elements'][0].get('distance', None):
|
121
143
|
distance_in_meters = response['rows'][0]['elements'][0]['distance']['value']
|
122
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
|
+
}
|
123
151
|
except Exception as e:
|
124
152
|
logger.error("geolocate.__get_google_distance: Error while getting distance from google", e)
|
125
|
-
|
126
|
-
return
|
153
|
+
distance_data = None
|
154
|
+
return distance_data
|
127
155
|
|
128
156
|
def __get_google_location(city, state, zipcode, country, logger):
|
129
157
|
try:
|
158
|
+
if (not city or not state) and not zipcode:
|
159
|
+
return None
|
130
160
|
loc_str = ''
|
161
|
+
data = None
|
131
162
|
|
132
163
|
if city:
|
133
164
|
loc_str = city
|
@@ -150,123 +181,6 @@ def __get_google_location(city, state, zipcode, country, logger):
|
|
150
181
|
|
151
182
|
loc_str = loc_str + country
|
152
183
|
|
153
|
-
def __parse_response(response):
|
154
|
-
if not response or len(response) == 0:
|
155
|
-
return None
|
156
|
-
'''
|
157
|
-
Sample response of Google Maps API for address: Cincinati, OH, 45204
|
158
|
-
{
|
159
|
-
"address_components": [
|
160
|
-
{
|
161
|
-
"long_name": "45204",
|
162
|
-
"short_name": "45204",
|
163
|
-
"types": [
|
164
|
-
"postal_code"
|
165
|
-
]
|
166
|
-
},
|
167
|
-
{
|
168
|
-
"long_name": "Cincinnati",
|
169
|
-
"short_name": "Cincinnati",
|
170
|
-
"types": [
|
171
|
-
"locality",
|
172
|
-
"political"
|
173
|
-
]
|
174
|
-
},
|
175
|
-
{
|
176
|
-
"long_name": "Hamilton County",
|
177
|
-
"short_name": "Hamilton County",
|
178
|
-
"types": [
|
179
|
-
"administrative_area_level_2",
|
180
|
-
"political"
|
181
|
-
]
|
182
|
-
},
|
183
|
-
{
|
184
|
-
"long_name": "Ohio",
|
185
|
-
"short_name": "OH",
|
186
|
-
"types": [
|
187
|
-
"administrative_area_level_1",
|
188
|
-
"political"
|
189
|
-
]
|
190
|
-
},
|
191
|
-
{
|
192
|
-
"long_name": "United States",
|
193
|
-
"short_name": "US",
|
194
|
-
"types": [
|
195
|
-
"country",
|
196
|
-
"political"
|
197
|
-
]
|
198
|
-
}
|
199
|
-
],
|
200
|
-
"formatted_address": "Cincinnati, OH 45204, USA",
|
201
|
-
"geometry": {
|
202
|
-
"bounds": {
|
203
|
-
"northeast": {
|
204
|
-
"lat": 39.1251898,
|
205
|
-
"lng": -84.539683
|
206
|
-
},
|
207
|
-
"southwest": {
|
208
|
-
"lat": 39.073286,
|
209
|
-
"lng": -84.62870989999999
|
210
|
-
}
|
211
|
-
},
|
212
|
-
"location": {
|
213
|
-
"lat": 39.0930395,
|
214
|
-
"lng": -84.56676650000001
|
215
|
-
},
|
216
|
-
"location_type": "APPROXIMATE",
|
217
|
-
"viewport": {
|
218
|
-
"northeast": {
|
219
|
-
"lat": 39.1251898,
|
220
|
-
"lng": -84.539683
|
221
|
-
},
|
222
|
-
"southwest": {
|
223
|
-
"lat": 39.073286,
|
224
|
-
"lng": -84.62870989999999
|
225
|
-
}
|
226
|
-
}
|
227
|
-
},
|
228
|
-
"place_id": "ChIJjYEP0hK2QYgRTJoYykoQeqw",
|
229
|
-
"postcode_localities": [
|
230
|
-
"Cincinnati",
|
231
|
-
"Queen City Square"
|
232
|
-
],
|
233
|
-
"types": [
|
234
|
-
"postal_code"
|
235
|
-
]
|
236
|
-
}
|
237
|
-
'''
|
238
|
-
components = response[0]['address_components']
|
239
|
-
types = response[0]['types']
|
240
|
-
location = response[0]['geometry']['location']
|
241
|
-
postcode_localities = response[0].get('postcode_localities', None)
|
242
|
-
|
243
|
-
data = { 'city': None, 'state': None, 'postcode': None }
|
244
|
-
data['lat'] = location['lat']
|
245
|
-
data['lng'] = location['lng']
|
246
|
-
|
247
|
-
# when checking the response for a zipcode verify the city name is in the list of localities
|
248
|
-
if 'postal_code' in types and postcode_localities and city:
|
249
|
-
matches = [l for l in components if (
|
250
|
-
'postal_localities' in l.get('types') and
|
251
|
-
(l.short_name.lower() == city.lower() or l.long_name.lower() == city.lower())
|
252
|
-
)]
|
253
|
-
city_present_in_postcode_localities = (city in postcode_localities)
|
254
|
-
|
255
|
-
if not matches and not city_present_in_postcode_localities:
|
256
|
-
return None
|
257
|
-
|
258
|
-
for component in components:
|
259
|
-
if 'locality' in component['types']:
|
260
|
-
data['city'] = component['short_name']
|
261
|
-
elif 'administrative_area_level_1' in component['types']:
|
262
|
-
data['state'] = component['short_name']
|
263
|
-
elif 'postcode' in component['types'] or 'postal_code' in component['types']:
|
264
|
-
data['postcode'] = component['short_name']
|
265
|
-
elif 'country' in component['types']:
|
266
|
-
data['country'] = component['short_name']
|
267
|
-
|
268
|
-
return data
|
269
|
-
|
270
184
|
gmaps = googlemaps.Client(key=app_config.GOOGLE_API_KEY)
|
271
185
|
response = gmaps.geocode(loc_str)
|
272
186
|
|
@@ -282,21 +196,7 @@ def __get_google_location(city, state, zipcode, country, logger):
|
|
282
196
|
logger.warning(f"Cannot select a single address from multiple for {loc_str}.")
|
283
197
|
return None
|
284
198
|
response = [selected_address]
|
285
|
-
|
286
|
-
data = __parse_response(response)
|
287
|
-
|
288
|
-
# For some locals like neighborhood google does not return postal_code
|
289
|
-
## if zipcode is present run it only and verify against city
|
290
|
-
if data and not data['postcode']:
|
291
|
-
if zipcode:
|
292
|
-
response = gmaps.geocode(zipcode)
|
293
|
-
else:
|
294
|
-
response = gmaps.reverse_geocode((data['lat'], data['lng']))
|
295
|
-
post_code_data = __parse_response(response)
|
296
|
-
data['postcode'] = post_code_data['postcode'] if post_code_data else None
|
297
|
-
if data['postcode']:
|
298
|
-
__cache_location(city, state, zipcode, data, logger)
|
299
|
-
return data
|
199
|
+
return __parse_response(response, city)
|
300
200
|
except googlemaps.exceptions.Timeout as e:
|
301
201
|
msg = "geolocate.__get_google_location - Location lookup timed out {0}, {1}, {2}: {3}".format(city, state, zipcode, e)
|
302
202
|
|
@@ -314,6 +214,123 @@ def __get_google_location(city, state, zipcode, country, logger):
|
|
314
214
|
|
315
215
|
return None
|
316
216
|
|
217
|
+
def __parse_response(response, city):
|
218
|
+
if not response or len(response) == 0:
|
219
|
+
return None
|
220
|
+
'''
|
221
|
+
Sample response of Google Maps API for address: Cincinati, OH, 45204
|
222
|
+
{
|
223
|
+
"address_components": [
|
224
|
+
{
|
225
|
+
"long_name": "45204",
|
226
|
+
"short_name": "45204",
|
227
|
+
"types": [
|
228
|
+
"postal_code"
|
229
|
+
]
|
230
|
+
},
|
231
|
+
{
|
232
|
+
"long_name": "Cincinnati",
|
233
|
+
"short_name": "Cincinnati",
|
234
|
+
"types": [
|
235
|
+
"locality",
|
236
|
+
"political"
|
237
|
+
]
|
238
|
+
},
|
239
|
+
{
|
240
|
+
"long_name": "Hamilton County",
|
241
|
+
"short_name": "Hamilton County",
|
242
|
+
"types": [
|
243
|
+
"administrative_area_level_2",
|
244
|
+
"political"
|
245
|
+
]
|
246
|
+
},
|
247
|
+
{
|
248
|
+
"long_name": "Ohio",
|
249
|
+
"short_name": "OH",
|
250
|
+
"types": [
|
251
|
+
"administrative_area_level_1",
|
252
|
+
"political"
|
253
|
+
]
|
254
|
+
},
|
255
|
+
{
|
256
|
+
"long_name": "United States",
|
257
|
+
"short_name": "US",
|
258
|
+
"types": [
|
259
|
+
"country",
|
260
|
+
"political"
|
261
|
+
]
|
262
|
+
}
|
263
|
+
],
|
264
|
+
"formatted_address": "Cincinnati, OH 45204, USA",
|
265
|
+
"geometry": {
|
266
|
+
"bounds": {
|
267
|
+
"northeast": {
|
268
|
+
"lat": 39.1251898,
|
269
|
+
"lng": -84.539683
|
270
|
+
},
|
271
|
+
"southwest": {
|
272
|
+
"lat": 39.073286,
|
273
|
+
"lng": -84.62870989999999
|
274
|
+
}
|
275
|
+
},
|
276
|
+
"location": {
|
277
|
+
"lat": 39.0930395,
|
278
|
+
"lng": -84.56676650000001
|
279
|
+
},
|
280
|
+
"location_type": "APPROXIMATE",
|
281
|
+
"viewport": {
|
282
|
+
"northeast": {
|
283
|
+
"lat": 39.1251898,
|
284
|
+
"lng": -84.539683
|
285
|
+
},
|
286
|
+
"southwest": {
|
287
|
+
"lat": 39.073286,
|
288
|
+
"lng": -84.62870989999999
|
289
|
+
}
|
290
|
+
}
|
291
|
+
},
|
292
|
+
"place_id": "ChIJjYEP0hK2QYgRTJoYykoQeqw",
|
293
|
+
"postcode_localities": [
|
294
|
+
"Cincinnati",
|
295
|
+
"Queen City Square"
|
296
|
+
],
|
297
|
+
"types": [
|
298
|
+
"postal_code"
|
299
|
+
]
|
300
|
+
}
|
301
|
+
'''
|
302
|
+
components = response[0]['address_components']
|
303
|
+
types = response[0]['types']
|
304
|
+
location = response[0]['geometry']['location']
|
305
|
+
postcode_localities = response[0].get('postcode_localities', None)
|
306
|
+
|
307
|
+
data = {'city': None, 'state': None, 'postcode': None}
|
308
|
+
data['lat'] = location['lat']
|
309
|
+
data['lng'] = location['lng']
|
310
|
+
|
311
|
+
# when checking the response for a zipcode verify the city name is in the list of localities
|
312
|
+
if 'postal_code' in types and postcode_localities and city:
|
313
|
+
matches = [l for l in components if (
|
314
|
+
'postal_localities' in l.get('types') and
|
315
|
+
(l.short_name.lower() == city.lower() or l.long_name.lower() == city.lower())
|
316
|
+
)]
|
317
|
+
city_present_in_postcode_localities = (city in postcode_localities)
|
318
|
+
|
319
|
+
if not matches and not city_present_in_postcode_localities:
|
320
|
+
return None
|
321
|
+
|
322
|
+
for component in components:
|
323
|
+
if 'locality' in component['types']:
|
324
|
+
data['city'] = component['short_name']
|
325
|
+
elif 'administrative_area_level_1' in component['types']:
|
326
|
+
data['state'] = component['short_name']
|
327
|
+
elif 'postcode' in component['types'] or 'postal_code' in component['types']:
|
328
|
+
data['postcode'] = component['short_name']
|
329
|
+
elif 'country' in component['types']:
|
330
|
+
data['country'] = component['short_name']
|
331
|
+
|
332
|
+
return data
|
333
|
+
|
317
334
|
def __cache_location(city, state, zipcode, location_data, logger):
|
318
335
|
location_string = __get_location_string(city, state, zipcode)
|
319
336
|
location_db_conn.set(location_string, str(location_data))
|
@@ -344,19 +361,22 @@ def __get_location_string(city, state, zipcode):
|
|
344
361
|
|
345
362
|
return location_string.lower()
|
346
363
|
|
347
|
-
def __cache_distance(distance_cache_key,
|
348
|
-
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))
|
349
366
|
|
350
367
|
def __get_distance_from_cache(distance_cache_key, logger):
|
351
|
-
|
368
|
+
distance_data = {}
|
352
369
|
try:
|
353
|
-
|
354
|
-
if
|
355
|
-
|
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)
|
356
376
|
except Exception as e:
|
357
377
|
logger.warn("geolocate.__get_distance_from_cache: Error while getting distance from cache", e)
|
358
|
-
|
359
|
-
return
|
378
|
+
distance_data = {}
|
379
|
+
return distance_data
|
360
380
|
|
361
381
|
def __get_distance_cache_key(origin_latitude, origin_longitude, destination_latitude, destination_longitude):
|
362
382
|
return f'{__truncate(origin_latitude)},{__truncate(origin_longitude)}->{__truncate(destination_latitude)},{__truncate(destination_longitude)}'
|
@@ -404,3 +424,20 @@ def __select_address(city, state, address_list):
|
|
404
424
|
and parsed_city_and_state['state'].strip().lower() == state.strip().lower():
|
405
425
|
return parsed_city_and_state['address']
|
406
426
|
return None
|
427
|
+
|
428
|
+
def __get_matching_location_from_cache(city, state, lat, lng, logger):
|
429
|
+
matching_location = None
|
430
|
+
try:
|
431
|
+
if city and state and lat and lng:
|
432
|
+
key = __get_location_string(city, state, None)
|
433
|
+
pattern = f'{key}*'
|
434
|
+
matching_keys = location_db_conn.keys(pattern)
|
435
|
+
if matching_keys:
|
436
|
+
for matching_key in matching_keys:
|
437
|
+
location = literal_eval(location_db_conn.get(matching_key).decode('utf-8'))
|
438
|
+
if location.get('lat') == lat and location.get('lng') == lng and location.get('postcode'):
|
439
|
+
matching_location = location
|
440
|
+
break
|
441
|
+
except Exception as e:
|
442
|
+
logger.warn("geolocate.__get_matching_location_from_cache: Failed: ", e)
|
443
|
+
return matching_location
|
@@ -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
|