bb-integrations-library 3.0.11__py3-none-any.whl
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.
- bb_integrations_lib/__init__.py +0 -0
- bb_integrations_lib/converters/__init__.py +0 -0
- bb_integrations_lib/gravitate/__init__.py +0 -0
- bb_integrations_lib/gravitate/base_api.py +20 -0
- bb_integrations_lib/gravitate/model.py +29 -0
- bb_integrations_lib/gravitate/pe_api.py +122 -0
- bb_integrations_lib/gravitate/rita_api.py +552 -0
- bb_integrations_lib/gravitate/sd_api.py +572 -0
- bb_integrations_lib/gravitate/testing/TTE/sd/models.py +1398 -0
- bb_integrations_lib/gravitate/testing/TTE/sd/tests/test_models.py +2987 -0
- bb_integrations_lib/gravitate/testing/__init__.py +0 -0
- bb_integrations_lib/gravitate/testing/builder.py +55 -0
- bb_integrations_lib/gravitate/testing/openapi.py +70 -0
- bb_integrations_lib/gravitate/testing/util.py +274 -0
- bb_integrations_lib/mappers/__init__.py +0 -0
- bb_integrations_lib/mappers/prices/__init__.py +0 -0
- bb_integrations_lib/mappers/prices/model.py +106 -0
- bb_integrations_lib/mappers/prices/price_mapper.py +127 -0
- bb_integrations_lib/mappers/prices/protocol.py +20 -0
- bb_integrations_lib/mappers/prices/util.py +61 -0
- bb_integrations_lib/mappers/rita_mapper.py +523 -0
- bb_integrations_lib/models/__init__.py +0 -0
- bb_integrations_lib/models/dtn_supplier_invoice.py +487 -0
- bb_integrations_lib/models/enums.py +28 -0
- bb_integrations_lib/models/pipeline_structs.py +76 -0
- bb_integrations_lib/models/probe/probe_event.py +20 -0
- bb_integrations_lib/models/probe/request_data.py +431 -0
- bb_integrations_lib/models/probe/resume_token.py +7 -0
- bb_integrations_lib/models/rita/audit.py +113 -0
- bb_integrations_lib/models/rita/auth.py +30 -0
- bb_integrations_lib/models/rita/bucket.py +17 -0
- bb_integrations_lib/models/rita/config.py +188 -0
- bb_integrations_lib/models/rita/constants.py +19 -0
- bb_integrations_lib/models/rita/crossroads_entities.py +293 -0
- bb_integrations_lib/models/rita/crossroads_mapping.py +428 -0
- bb_integrations_lib/models/rita/crossroads_monitoring.py +78 -0
- bb_integrations_lib/models/rita/crossroads_network.py +41 -0
- bb_integrations_lib/models/rita/crossroads_rules.py +80 -0
- bb_integrations_lib/models/rita/email.py +39 -0
- bb_integrations_lib/models/rita/issue.py +63 -0
- bb_integrations_lib/models/rita/mapping.py +227 -0
- bb_integrations_lib/models/rita/probe.py +58 -0
- bb_integrations_lib/models/rita/reference_data.py +110 -0
- bb_integrations_lib/models/rita/source_system.py +9 -0
- bb_integrations_lib/models/rita/workers.py +76 -0
- bb_integrations_lib/models/sd/bols_and_drops.py +241 -0
- bb_integrations_lib/models/sd/get_order.py +301 -0
- bb_integrations_lib/models/sd/orders.py +18 -0
- bb_integrations_lib/models/sd_api.py +115 -0
- bb_integrations_lib/pipelines/__init__.py +0 -0
- bb_integrations_lib/pipelines/parsers/__init__.py +0 -0
- bb_integrations_lib/pipelines/parsers/distribution_report/__init__.py +0 -0
- bb_integrations_lib/pipelines/parsers/distribution_report/order_by_site_product_parser.py +50 -0
- bb_integrations_lib/pipelines/parsers/distribution_report/tank_configs_parser.py +47 -0
- bb_integrations_lib/pipelines/parsers/dtn/__init__.py +0 -0
- bb_integrations_lib/pipelines/parsers/dtn/dtn_price_parser.py +102 -0
- bb_integrations_lib/pipelines/parsers/dtn/model.py +79 -0
- bb_integrations_lib/pipelines/parsers/price_engine/__init__.py +0 -0
- bb_integrations_lib/pipelines/parsers/price_engine/parse_accessorials_prices_parser.py +67 -0
- bb_integrations_lib/pipelines/parsers/price_engine/price_file_upload/__init__.py +0 -0
- bb_integrations_lib/pipelines/parsers/price_engine/price_file_upload/price_merge_parser.py +111 -0
- bb_integrations_lib/pipelines/parsers/price_engine/price_file_upload/price_sync_parser.py +107 -0
- bb_integrations_lib/pipelines/parsers/price_engine/price_file_upload/shared.py +81 -0
- bb_integrations_lib/pipelines/parsers/tank_reading_parser.py +155 -0
- bb_integrations_lib/pipelines/parsers/tank_sales_parser.py +144 -0
- bb_integrations_lib/pipelines/shared/__init__.py +0 -0
- bb_integrations_lib/pipelines/shared/allocation_matching.py +227 -0
- bb_integrations_lib/pipelines/shared/bol_allocation.py +2793 -0
- bb_integrations_lib/pipelines/steps/__init__.py +0 -0
- bb_integrations_lib/pipelines/steps/create_accessorials_step.py +80 -0
- bb_integrations_lib/pipelines/steps/distribution_report/__init__.py +0 -0
- bb_integrations_lib/pipelines/steps/distribution_report/distribution_report_datafram_to_raw_data.py +33 -0
- bb_integrations_lib/pipelines/steps/distribution_report/get_model_history_step.py +50 -0
- bb_integrations_lib/pipelines/steps/distribution_report/get_order_by_site_product_step.py +62 -0
- bb_integrations_lib/pipelines/steps/distribution_report/get_tank_configs_step.py +40 -0
- bb_integrations_lib/pipelines/steps/distribution_report/join_distribution_order_dos_step.py +85 -0
- bb_integrations_lib/pipelines/steps/distribution_report/upload_distribution_report_datafram_to_big_query.py +47 -0
- bb_integrations_lib/pipelines/steps/echo_step.py +14 -0
- bb_integrations_lib/pipelines/steps/export_dataframe_to_rawdata_step.py +28 -0
- bb_integrations_lib/pipelines/steps/exporting/__init__.py +0 -0
- bb_integrations_lib/pipelines/steps/exporting/bbd_export_payroll_file_step.py +107 -0
- bb_integrations_lib/pipelines/steps/exporting/bbd_export_readings_step.py +236 -0
- bb_integrations_lib/pipelines/steps/exporting/cargas_wholesale_bundle_upload_step.py +33 -0
- bb_integrations_lib/pipelines/steps/exporting/dataframe_flat_file_export.py +29 -0
- bb_integrations_lib/pipelines/steps/exporting/gcs_bucket_export_file_step.py +34 -0
- bb_integrations_lib/pipelines/steps/exporting/keyvu_export_step.py +356 -0
- bb_integrations_lib/pipelines/steps/exporting/pe_price_export_step.py +238 -0
- bb_integrations_lib/pipelines/steps/exporting/platform_science_order_sync_step.py +500 -0
- bb_integrations_lib/pipelines/steps/exporting/save_rawdata_to_disk.py +15 -0
- bb_integrations_lib/pipelines/steps/exporting/sftp_export_file_step.py +60 -0
- bb_integrations_lib/pipelines/steps/exporting/sftp_export_many_files_step.py +23 -0
- bb_integrations_lib/pipelines/steps/exporting/update_exported_orders_table_step.py +64 -0
- bb_integrations_lib/pipelines/steps/filter_step.py +22 -0
- bb_integrations_lib/pipelines/steps/get_latest_sync_date.py +34 -0
- bb_integrations_lib/pipelines/steps/importing/bbd_import_payroll_step.py +30 -0
- bb_integrations_lib/pipelines/steps/importing/get_order_numbers_to_export_step.py +138 -0
- bb_integrations_lib/pipelines/steps/importing/load_file_to_dataframe_step.py +46 -0
- bb_integrations_lib/pipelines/steps/importing/load_imap_attachment_step.py +172 -0
- bb_integrations_lib/pipelines/steps/importing/pe_bulk_sync_price_structure_step.py +68 -0
- bb_integrations_lib/pipelines/steps/importing/pe_price_merge_step.py +86 -0
- bb_integrations_lib/pipelines/steps/importing/sftp_file_config_step.py +124 -0
- bb_integrations_lib/pipelines/steps/importing/test_exact_file_match.py +57 -0
- bb_integrations_lib/pipelines/steps/null_step.py +15 -0
- bb_integrations_lib/pipelines/steps/pe_integration_job_step.py +32 -0
- bb_integrations_lib/pipelines/steps/processing/__init__.py +0 -0
- bb_integrations_lib/pipelines/steps/processing/archive_gcs_step.py +76 -0
- bb_integrations_lib/pipelines/steps/processing/archive_sftp_step.py +48 -0
- bb_integrations_lib/pipelines/steps/processing/bbd_format_tank_readings_step.py +492 -0
- bb_integrations_lib/pipelines/steps/processing/bbd_upload_prices_step.py +54 -0
- bb_integrations_lib/pipelines/steps/processing/bbd_upload_tank_sales_step.py +124 -0
- bb_integrations_lib/pipelines/steps/processing/bbd_upload_tankreading_step.py +80 -0
- bb_integrations_lib/pipelines/steps/processing/convert_bbd_order_to_cargas_step.py +226 -0
- bb_integrations_lib/pipelines/steps/processing/delete_sftp_step.py +33 -0
- bb_integrations_lib/pipelines/steps/processing/dtn/__init__.py +2 -0
- bb_integrations_lib/pipelines/steps/processing/dtn/convert_dtn_invoice_to_sd_model.py +145 -0
- bb_integrations_lib/pipelines/steps/processing/dtn/parse_dtn_invoice_step.py +38 -0
- bb_integrations_lib/pipelines/steps/processing/file_config_parser_step.py +720 -0
- bb_integrations_lib/pipelines/steps/processing/file_config_parser_step_v2.py +418 -0
- bb_integrations_lib/pipelines/steps/processing/get_sd_price_price_request.py +105 -0
- bb_integrations_lib/pipelines/steps/processing/keyvu_upload_deliveryplan_step.py +39 -0
- bb_integrations_lib/pipelines/steps/processing/mark_orders_exported_in_bbd_step.py +185 -0
- bb_integrations_lib/pipelines/steps/processing/pe_price_rows_processing_step.py +174 -0
- bb_integrations_lib/pipelines/steps/processing/send_process_report_step.py +47 -0
- bb_integrations_lib/pipelines/steps/processing/sftp_renamer_step.py +61 -0
- bb_integrations_lib/pipelines/steps/processing/tank_reading_touchup_steps.py +75 -0
- bb_integrations_lib/pipelines/steps/processing/upload_supplier_invoice_step.py +16 -0
- bb_integrations_lib/pipelines/steps/send_attached_in_rita_email_step.py +44 -0
- bb_integrations_lib/pipelines/steps/send_rita_email_step.py +34 -0
- bb_integrations_lib/pipelines/steps/sleep_step.py +24 -0
- bb_integrations_lib/pipelines/wrappers/__init__.py +0 -0
- bb_integrations_lib/pipelines/wrappers/accessorials_transformation.py +104 -0
- bb_integrations_lib/pipelines/wrappers/distribution_report.py +191 -0
- bb_integrations_lib/pipelines/wrappers/export_tank_readings.py +237 -0
- bb_integrations_lib/pipelines/wrappers/import_tank_readings.py +192 -0
- bb_integrations_lib/pipelines/wrappers/wrapper.py +81 -0
- bb_integrations_lib/protocols/__init__.py +0 -0
- bb_integrations_lib/protocols/flat_file.py +210 -0
- bb_integrations_lib/protocols/gravitate_client.py +104 -0
- bb_integrations_lib/protocols/pipelines.py +697 -0
- bb_integrations_lib/provider/__init__.py +0 -0
- bb_integrations_lib/provider/api/__init__.py +0 -0
- bb_integrations_lib/provider/api/cargas/__init__.py +0 -0
- bb_integrations_lib/provider/api/cargas/client.py +43 -0
- bb_integrations_lib/provider/api/cargas/model.py +49 -0
- bb_integrations_lib/provider/api/cargas/protocol.py +23 -0
- bb_integrations_lib/provider/api/dtn/__init__.py +0 -0
- bb_integrations_lib/provider/api/dtn/client.py +128 -0
- bb_integrations_lib/provider/api/dtn/protocol.py +9 -0
- bb_integrations_lib/provider/api/keyvu/__init__.py +0 -0
- bb_integrations_lib/provider/api/keyvu/client.py +30 -0
- bb_integrations_lib/provider/api/keyvu/model.py +149 -0
- bb_integrations_lib/provider/api/macropoint/__init__.py +0 -0
- bb_integrations_lib/provider/api/macropoint/client.py +28 -0
- bb_integrations_lib/provider/api/macropoint/model.py +40 -0
- bb_integrations_lib/provider/api/pc_miler/__init__.py +0 -0
- bb_integrations_lib/provider/api/pc_miler/client.py +130 -0
- bb_integrations_lib/provider/api/pc_miler/model.py +6 -0
- bb_integrations_lib/provider/api/pc_miler/web_services_apis.py +131 -0
- bb_integrations_lib/provider/api/platform_science/__init__.py +0 -0
- bb_integrations_lib/provider/api/platform_science/client.py +147 -0
- bb_integrations_lib/provider/api/platform_science/model.py +82 -0
- bb_integrations_lib/provider/api/quicktrip/__init__.py +0 -0
- bb_integrations_lib/provider/api/quicktrip/client.py +52 -0
- bb_integrations_lib/provider/api/telapoint/__init__.py +0 -0
- bb_integrations_lib/provider/api/telapoint/client.py +68 -0
- bb_integrations_lib/provider/api/telapoint/model.py +178 -0
- bb_integrations_lib/provider/api/warren_rogers/__init__.py +0 -0
- bb_integrations_lib/provider/api/warren_rogers/client.py +207 -0
- bb_integrations_lib/provider/aws/__init__.py +0 -0
- bb_integrations_lib/provider/aws/s3/__init__.py +0 -0
- bb_integrations_lib/provider/aws/s3/client.py +126 -0
- bb_integrations_lib/provider/ftp/__init__.py +0 -0
- bb_integrations_lib/provider/ftp/client.py +140 -0
- bb_integrations_lib/provider/ftp/interface.py +273 -0
- bb_integrations_lib/provider/ftp/model.py +76 -0
- bb_integrations_lib/provider/imap/__init__.py +0 -0
- bb_integrations_lib/provider/imap/client.py +228 -0
- bb_integrations_lib/provider/imap/model.py +3 -0
- bb_integrations_lib/provider/sqlserver/__init__.py +0 -0
- bb_integrations_lib/provider/sqlserver/client.py +106 -0
- bb_integrations_lib/secrets/__init__.py +4 -0
- bb_integrations_lib/secrets/adapters.py +98 -0
- bb_integrations_lib/secrets/credential_models.py +222 -0
- bb_integrations_lib/secrets/factory.py +85 -0
- bb_integrations_lib/secrets/providers.py +160 -0
- bb_integrations_lib/shared/__init__.py +0 -0
- bb_integrations_lib/shared/exceptions.py +25 -0
- bb_integrations_lib/shared/model.py +1039 -0
- bb_integrations_lib/shared/shared_enums.py +510 -0
- bb_integrations_lib/storage/README.md +236 -0
- bb_integrations_lib/storage/__init__.py +0 -0
- bb_integrations_lib/storage/aws/__init__.py +0 -0
- bb_integrations_lib/storage/aws/s3.py +8 -0
- bb_integrations_lib/storage/defaults.py +72 -0
- bb_integrations_lib/storage/gcs/__init__.py +0 -0
- bb_integrations_lib/storage/gcs/client.py +8 -0
- bb_integrations_lib/storage/gcsmanager/__init__.py +0 -0
- bb_integrations_lib/storage/gcsmanager/client.py +8 -0
- bb_integrations_lib/storage/setup.py +29 -0
- bb_integrations_lib/util/__init__.py +0 -0
- bb_integrations_lib/util/cache/__init__.py +0 -0
- bb_integrations_lib/util/cache/custom_ttl_cache.py +75 -0
- bb_integrations_lib/util/cache/protocol.py +9 -0
- bb_integrations_lib/util/config/__init__.py +0 -0
- bb_integrations_lib/util/config/manager.py +391 -0
- bb_integrations_lib/util/config/model.py +41 -0
- bb_integrations_lib/util/exception_logger/__init__.py +0 -0
- bb_integrations_lib/util/exception_logger/exception_logger.py +146 -0
- bb_integrations_lib/util/exception_logger/test.py +114 -0
- bb_integrations_lib/util/utils.py +364 -0
- bb_integrations_lib/workers/__init__.py +0 -0
- bb_integrations_lib/workers/groups.py +13 -0
- bb_integrations_lib/workers/rpc_worker.py +50 -0
- bb_integrations_lib/workers/topics.py +20 -0
- bb_integrations_library-3.0.11.dist-info/METADATA +59 -0
- bb_integrations_library-3.0.11.dist-info/RECORD +217 -0
- bb_integrations_library-3.0.11.dist-info/WHEEL +4 -0
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
|
|
3
|
+
from bb_integrations_lib.provider.api.cargas.model import CreateWholesaleTicketRequest, CreateWholesaleFeeLineRequest, \
|
|
4
|
+
CreateWholesaleLineRequest
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CargasClient(httpx.AsyncClient):
|
|
8
|
+
def __init__(self,
|
|
9
|
+
api_key: str,
|
|
10
|
+
base_url: str = " https://cargase.aeroenergy.com/cargasenergy/API"):
|
|
11
|
+
super().__init__(base_url=base_url)
|
|
12
|
+
self.api_key = api_key
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def custom_headers(self) -> dict:
|
|
16
|
+
return {
|
|
17
|
+
'APIKey': self.api_key,
|
|
18
|
+
'Content-Type': 'application/json'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async def create_wholesale_ticket(self, data: CreateWholesaleTicketRequest) -> dict:
|
|
22
|
+
url = '/CreateWholesaleTicket'
|
|
23
|
+
res = await self.post(
|
|
24
|
+
url=url, headers=self.custom_headers, json=data.model_dump(exclude_none=True, mode="json")
|
|
25
|
+
)
|
|
26
|
+
res.raise_for_status()
|
|
27
|
+
return res.json()
|
|
28
|
+
|
|
29
|
+
async def create_wholesale_line(self, data: CreateWholesaleLineRequest) -> dict:
|
|
30
|
+
url = '/CreateWholesaleLine'
|
|
31
|
+
res = await self.post(
|
|
32
|
+
url=url, headers=self.custom_headers, json=data.model_dump(exclude_none=True, mode="json")
|
|
33
|
+
)
|
|
34
|
+
res.raise_for_status()
|
|
35
|
+
return res.json()
|
|
36
|
+
|
|
37
|
+
async def create_wholesale_fee_line(self, data: CreateWholesaleFeeLineRequest) -> dict:
|
|
38
|
+
url = '/CreateWholesaleFeeLine'
|
|
39
|
+
res = await self.post(
|
|
40
|
+
url=url, headers=self.custom_headers, json=data.model_dump(exclude_none=True, mode="json")
|
|
41
|
+
)
|
|
42
|
+
res.raise_for_status()
|
|
43
|
+
return res.json()
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CreateWholesaleFeeLineRequest(BaseModel):
|
|
8
|
+
DocumentID: str
|
|
9
|
+
ItemID: str
|
|
10
|
+
Quantity: Optional[float] = None
|
|
11
|
+
UnitPrice: Optional[float] = None
|
|
12
|
+
UserName: str
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CreateWholesaleLineRequest(BaseModel):
|
|
16
|
+
DocumentID: int
|
|
17
|
+
ItemID: int
|
|
18
|
+
TankID: int
|
|
19
|
+
Quantity: float
|
|
20
|
+
QuantityGross: float
|
|
21
|
+
UnitPrice: Optional[float] = None
|
|
22
|
+
FreightRateID: Optional[float] = None
|
|
23
|
+
VendorLocationID: Optional[float] = None
|
|
24
|
+
FreightAmount: Optional[float] = None
|
|
25
|
+
SurchargeAmount: Optional[float] = None
|
|
26
|
+
UnitCostOverride: Optional[float] = None
|
|
27
|
+
CustomerPricingID: Optional[str] = None
|
|
28
|
+
UserName: str
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class CreateWholesaleTicketRequest(BaseModel):
|
|
32
|
+
CustomerID: int
|
|
33
|
+
DeliveryDate: datetime
|
|
34
|
+
CustomerPONumber: Optional[str] = None
|
|
35
|
+
DriverID: Optional[int] = None
|
|
36
|
+
WholesaleTruckID: Optional[int] = None
|
|
37
|
+
Message: Optional[str] = None
|
|
38
|
+
InvoiceNotes: Optional[str] = None
|
|
39
|
+
CostCenterID: Optional[int] = None
|
|
40
|
+
SubTypeID: Optional[int] = None
|
|
41
|
+
SalespersonID: Optional[int] = None
|
|
42
|
+
AdditionalNotes: Optional[str] = None
|
|
43
|
+
UserName: str
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class CreateWholesaleTicketRequestBundle(BaseModel):
|
|
47
|
+
ticket_request: CreateWholesaleTicketRequest
|
|
48
|
+
line_requests: list[CreateWholesaleLineRequest] = []
|
|
49
|
+
fee_line_requests: list[CreateWholesaleLineRequest] = []
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from bb_integrations_lib.provider.api.cargas.model import CreateWholesaleTicketRequest, CreateWholesaleLineRequest, \
|
|
2
|
+
CreateWholesaleFeeLineRequest
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class CargasClient():
|
|
6
|
+
def __init__(self,
|
|
7
|
+
api_key: str,
|
|
8
|
+
base_url: str = " https://cargase.aeroenergy.com/cargasenergy/API"):
|
|
9
|
+
self.base_url = base_url
|
|
10
|
+
self.api_key = api_key
|
|
11
|
+
|
|
12
|
+
@property
|
|
13
|
+
def custom_headers(self) -> dict:
|
|
14
|
+
return {
|
|
15
|
+
'APIKey': self.api_key,
|
|
16
|
+
'Content-Type': 'application/json'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async def create_wholesale_ticket(self, data: CreateWholesaleTicketRequest): ...
|
|
20
|
+
|
|
21
|
+
async def create_wholesale_line(self, data: CreateWholesaleLineRequest): ...
|
|
22
|
+
|
|
23
|
+
async def create_wholesale_fee_line(self, data: CreateWholesaleFeeLineRequest): ...
|
|
File without changes
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from contextlib import contextmanager
|
|
3
|
+
from typing import Dict, List
|
|
4
|
+
import httpx
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
class DTNClient(httpx.AsyncClient):
|
|
8
|
+
def __init__(
|
|
9
|
+
self, username: str,
|
|
10
|
+
web_service_key: str,
|
|
11
|
+
api_key: str,
|
|
12
|
+
base_url: str,
|
|
13
|
+
timeout: float = 180.0,
|
|
14
|
+
):
|
|
15
|
+
super().__init__(base_url=base_url)
|
|
16
|
+
self.username = username
|
|
17
|
+
self.web_service_key = web_service_key
|
|
18
|
+
self.api_key = api_key
|
|
19
|
+
self.base_url = base_url.rstrip("/")
|
|
20
|
+
self.client = httpx.AsyncClient(timeout=180)
|
|
21
|
+
self.timeout = httpx.Timeout(timeout, connect=60.0)
|
|
22
|
+
|
|
23
|
+
def __repr__(self):
|
|
24
|
+
return """DTN API Client designed for DTN Allocation Tracker"""
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def custom_headers(self) -> Dict[str, str]:
|
|
28
|
+
return {
|
|
29
|
+
'username': self.username,
|
|
30
|
+
'Accept': 'application/vnd.dtn.energy.v1+JSON',
|
|
31
|
+
'webservicekey': self.web_service_key,
|
|
32
|
+
'apikey': self.api_key,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async def get_allocations(self) -> List[Dict]:
|
|
36
|
+
url = '/allocations'
|
|
37
|
+
res = await self.get(url=url, headers=self.custom_headers, timeout=self.timeout)
|
|
38
|
+
return res.json()
|
|
39
|
+
|
|
40
|
+
async def get_data_in_group(self, url: str) -> List[Dict]:
|
|
41
|
+
if url.startswith(self.base_url):
|
|
42
|
+
url = url.removeprefix(self.base_url)
|
|
43
|
+
if not url.startswith('/'):
|
|
44
|
+
url = f'/{url}'
|
|
45
|
+
res = await self.get(
|
|
46
|
+
url=url,
|
|
47
|
+
headers=self.custom_headers,
|
|
48
|
+
timeout=self.timeout
|
|
49
|
+
)
|
|
50
|
+
return res.json()
|
|
51
|
+
|
|
52
|
+
async def get_terminal(self, href) -> Dict:
|
|
53
|
+
res = await self.get(url=href, headers=self.custom_headers, timeout=self.timeout)
|
|
54
|
+
return res.json()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@contextmanager
|
|
59
|
+
def init_dtn_api(username=None, web_service_key=None, api_key=None) -> DTNClient:
|
|
60
|
+
dtn_client = DTNClient(
|
|
61
|
+
username=username,
|
|
62
|
+
web_service_key=web_service_key,
|
|
63
|
+
api_key=api_key,
|
|
64
|
+
base_url='https://api.dtn.com/fuelsuite/allocationtracker/'
|
|
65
|
+
)
|
|
66
|
+
yield dtn_client
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def parse_allocation_data(allocation_data):
|
|
70
|
+
ret = []
|
|
71
|
+
for allocation in allocation_data['data']:
|
|
72
|
+
supplier = allocation.get('supplier', {})
|
|
73
|
+
location_data = allocation.get('location', {})
|
|
74
|
+
customer_data = allocation.get('customer', {})
|
|
75
|
+
consignee_group_data = customer_data.get('consigneeGroup', {})
|
|
76
|
+
product_group_data = allocation.get('productAllocationList', [])
|
|
77
|
+
terminal_data = location_data.get('terminal', {}) or {}
|
|
78
|
+
location_group_data = location_data.get('terminalGroup', {}) or {}
|
|
79
|
+
sold_to_data = consignee_group_data.get('soldTo', {}) or {}
|
|
80
|
+
supplier_name = supplier.get('name')
|
|
81
|
+
supplier_code = supplier.get('sellerNum')
|
|
82
|
+
terminal_name = location_group_data.get('name') or terminal_data.get('name') or None
|
|
83
|
+
terminal_code = location_group_data.get('id') or terminal_data.get('id') or None
|
|
84
|
+
terminal_hfref = location_group_data.get('terminalListLink', {}).get('href')
|
|
85
|
+
consignee_name = consignee_group_data.get('name')
|
|
86
|
+
consignee_id = consignee_group_data.get('id')
|
|
87
|
+
sold_to_id = sold_to_data.get('id')
|
|
88
|
+
sold_to_name = sold_to_data.get('name')
|
|
89
|
+
for group in product_group_data:
|
|
90
|
+
product_group_name = group.get('name')
|
|
91
|
+
uom = group.get('unitOfMeasure')
|
|
92
|
+
allocation_remaining_monthly = group.get('allocationRemainingAmountMonthly')
|
|
93
|
+
lifted_amount_monthly = group.get('liftedAmountMonthly')
|
|
94
|
+
refresh_amount_monthly = group.get('refreshAmountMonthly')
|
|
95
|
+
refresh_date_monthly = group.get('refreshDateMonthly')
|
|
96
|
+
scaled_start_amount_monthly = group.get('scaledStartAmountMonthly')
|
|
97
|
+
start_amount_monthly = group.get('startAmountMonthly')
|
|
98
|
+
row = {
|
|
99
|
+
'supplier_name': supplier_name,
|
|
100
|
+
'supplier_code': supplier_code,
|
|
101
|
+
'terminal_name': terminal_name,
|
|
102
|
+
'terminal_code': terminal_code,
|
|
103
|
+
'terminal_hfref': terminal_hfref,
|
|
104
|
+
'consignee_name': consignee_name,
|
|
105
|
+
'consignee_id': consignee_id,
|
|
106
|
+
'sold_to_name': sold_to_name,
|
|
107
|
+
'sold_to_id': sold_to_id,
|
|
108
|
+
'product_group_name': product_group_name,
|
|
109
|
+
'uom': uom,
|
|
110
|
+
'allocation_remaining_monthly': allocation_remaining_monthly,
|
|
111
|
+
'lifted_amount_monthly': lifted_amount_monthly,
|
|
112
|
+
'refresh_amount_monthly': refresh_amount_monthly,
|
|
113
|
+
'refresh_date_monthly': refresh_date_monthly,
|
|
114
|
+
'scaled_start_amount_monthly': scaled_start_amount_monthly,
|
|
115
|
+
'start_amount_monthly': start_amount_monthly,
|
|
116
|
+
}
|
|
117
|
+
ret.append(row)
|
|
118
|
+
return pd.DataFrame(ret)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
if __name__ == "__main__":
|
|
122
|
+
async def get_allocation_data():
|
|
123
|
+
with init_dtn_api(username="", web_service_key="", api_key="") as dtn_client:
|
|
124
|
+
allocations = await dtn_client.get_allocations()
|
|
125
|
+
print(allocations)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
asyncio.run(get_allocation_data())
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
from httpx import Request, Response
|
|
3
|
+
|
|
4
|
+
from bb_integrations_lib.provider.api.keyvu.model import KeyVuDeliveryPlan, default_serialization_options
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class KeyVuAuth(httpx.Auth):
|
|
8
|
+
def __init__(self, token):
|
|
9
|
+
self.token = token
|
|
10
|
+
|
|
11
|
+
def auth_flow(self, request: Request):
|
|
12
|
+
request.headers["Keyvu-Api-Key"] = self.token
|
|
13
|
+
yield request
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class KeyVuClient:
|
|
17
|
+
def __init__(self, api_key: str):
|
|
18
|
+
self.base_url = ""
|
|
19
|
+
self.api_key = api_key
|
|
20
|
+
self.client = httpx.AsyncClient(auth=KeyVuAuth(self.api_key))
|
|
21
|
+
|
|
22
|
+
def build_url(self, tail: str) -> str:
|
|
23
|
+
return f"{self.base_url}/{tail}"
|
|
24
|
+
|
|
25
|
+
async def upload_deliveryplan(self, data: KeyVuDeliveryPlan, override_filename: str | None = None) -> Response:
|
|
26
|
+
return await self.client.post(
|
|
27
|
+
url=self.build_url("upload/deliveryplan"),
|
|
28
|
+
content=data.to_xml(**default_serialization_options),
|
|
29
|
+
headers={"filename": override_filename} if override_filename else {}
|
|
30
|
+
)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
# from pydantic import BaseModel
|
|
6
|
+
from pydantic_xml import BaseXmlModel, element
|
|
7
|
+
|
|
8
|
+
default_serialization_options = {
|
|
9
|
+
"skip_empty": False, "exclude_none": False, "exclude_unset": True
|
|
10
|
+
}
|
|
11
|
+
"""To be passed to pydantic_xml.BaseXmlModel.to_xml when sending to the KeyVu API"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DeliveryStatus(str, Enum):
|
|
15
|
+
planned = "Planned"
|
|
16
|
+
on_route_not_loaded = "OnRouteNotLoaded"
|
|
17
|
+
loading = "Loading"
|
|
18
|
+
on_route_loaded = "OnRouteLoaded"
|
|
19
|
+
unloading = "Unloading"
|
|
20
|
+
delivered = "Delivered"
|
|
21
|
+
confirmed = "Confirmed"
|
|
22
|
+
canceled = "Canceled"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class UnitSystem(str, Enum):
|
|
26
|
+
metric = "Metric"
|
|
27
|
+
imperial = "Imperial"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class KeyVuDeliveryPlan(BaseXmlModel, tag="Loads", nsmap={"": "http://keyvu.com/schemas/carrierloads/v6",
|
|
31
|
+
"xsi": "http://www.w3.org/2001/XMLSchema-instance",
|
|
32
|
+
"xsd": "http://www.w3.org/2001/XMLSchema"}):
|
|
33
|
+
start_date: datetime = element(tag="StartDate")
|
|
34
|
+
end_date: datetime = element(tag="EndDate")
|
|
35
|
+
export_date: datetime = element(tag="ExportDate")
|
|
36
|
+
deliveries: Optional[list["Delivery"]] = element(tag="Delivery", default=None, nillable=True)
|
|
37
|
+
|
|
38
|
+
class GeoLocation(BaseXmlModel):
|
|
39
|
+
longitude: Optional[float] = element(tag="Longitude", nillable=True, default=None)
|
|
40
|
+
latitude: Optional[float] = element(tag="Latitude", nillable=True, default=None)
|
|
41
|
+
heading: Optional[float] = element(tag="Heading", nillable=True, default=None)
|
|
42
|
+
last_updated: Optional[datetime] = element(tag="LastUpdated", nillable=True, default=None)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class Delivery(BaseXmlModel):
|
|
46
|
+
id: str = element(tag="Id")
|
|
47
|
+
carrier_name: Optional[str] = element(tag="CarrierName", default=None)
|
|
48
|
+
scac: Optional[str] = element(tag="Scac", default=None)
|
|
49
|
+
station_deliveries_array: "StationDeliveryArray" = element(tag="StationDeliveries", default=None)
|
|
50
|
+
trailer: Optional[str] = element(tag="Trailer", default=None)
|
|
51
|
+
last_updated: datetime = element(tag="LastUpdated")
|
|
52
|
+
geo_location: "GeoLocation" = element(tag="GeoLocation", default_factory=lambda: GeoLocation(longitude=None, latitude=None, heading=None, last_updated=None))
|
|
53
|
+
unit: str = element(tag="Unit")
|
|
54
|
+
|
|
55
|
+
def __init__(self, station_deliveries: list["StationDelivery"], **kwargs):
|
|
56
|
+
super().__init__(**kwargs)
|
|
57
|
+
self.station_deliveries = station_deliveries
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def station_deliveries(self) -> list["StationDelivery"] | None:
|
|
61
|
+
return self.station_deliveries_array.station_deliveries
|
|
62
|
+
|
|
63
|
+
@station_deliveries.setter
|
|
64
|
+
def station_deliveries(self, new_deliveries: list["StationDelivery"]) -> None:
|
|
65
|
+
self.station_deliveries_array = StationDeliveryArray(station_deliveries=new_deliveries)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class StationDeliveryArray(BaseXmlModel):
|
|
69
|
+
station_deliveries: Optional[list["StationDelivery"]] = element(tag="StationDelivery", default=None)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class StationDelivery(BaseXmlModel):
|
|
73
|
+
delivery_status: DeliveryStatus = element(tag="DeliveryStatus")
|
|
74
|
+
site_id: Optional[str] = element(tag="SiteId", default=None)
|
|
75
|
+
details_array: Optional["StationDeliveryDetailsArray"] = element(tag="Details", default=None)
|
|
76
|
+
bill_of_ladings_array: Optional["StationDeliveryBOLArray"] = element(tag="BillOfLadings", default=None)
|
|
77
|
+
tractor: Optional[str] = element(tag="Tractor", default=None)
|
|
78
|
+
delivery_date: datetime = element(tag="DeliveryDate")
|
|
79
|
+
carrier_delivery_status: Optional[str] = element(tag="CarrierDeliveryStatus", default=None)
|
|
80
|
+
|
|
81
|
+
def __init__(self, details: list["StationDeliveryDetails"] | None = None,
|
|
82
|
+
bill_of_ladings: list["StationDeliveryBOL"] | None = None, **kwargs):
|
|
83
|
+
super().__init__(**kwargs)
|
|
84
|
+
self.details = details
|
|
85
|
+
self.bill_of_ladings = bill_of_ladings
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def details(self) -> list["StationDeliveryDetails"] | None:
|
|
89
|
+
if not self.details_array:
|
|
90
|
+
return None
|
|
91
|
+
return self.details_array.details
|
|
92
|
+
|
|
93
|
+
@details.setter
|
|
94
|
+
def details(self, new_details: list["StationDeliveryDetails"]) -> None:
|
|
95
|
+
self.details_array = StationDeliveryDetailsArray(details=new_details)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def bill_of_ladings(self) -> list["StationDeliveryBOL"] | None:
|
|
99
|
+
if not self.bill_of_ladings_array:
|
|
100
|
+
return None
|
|
101
|
+
return self.bill_of_ladings_array.bill_of_ladings
|
|
102
|
+
|
|
103
|
+
@bill_of_ladings.setter
|
|
104
|
+
def bill_of_ladings(self, new_bols: list["StationDeliveryBOL"]) -> None:
|
|
105
|
+
self.bill_of_ladings_array = StationDeliveryBOLArray(bill_of_ladings=new_bols)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class StationDeliveryDetailsArray(BaseXmlModel):
|
|
109
|
+
details: Optional[list["StationDeliveryDetails"]] = element(tag="StationDeliveryDetails", default=None)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class StationDeliveryDetails(BaseXmlModel, tag="StationDeliveryDetails", skip_empty=True):
|
|
113
|
+
delivered_volume: Optional[float] = element(tag="DeliveredVolume", nillable=True)
|
|
114
|
+
volume_unit: UnitSystem = element(tag="VolumeUnit")
|
|
115
|
+
tank_sequence: Optional[int] = element(tag="TankSequence", default=None)
|
|
116
|
+
product_id: Optional[str] = element(tag="ProductId", default=None)
|
|
117
|
+
product: Optional[str] = element(tag="Product", default=None)
|
|
118
|
+
is_retained: bool = element(tag="IsRetained")
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def from_v1_order_dict(details: dict) -> "StationDeliveryDetails":
|
|
122
|
+
# Prefer using tank sequence, but fall back to product ID based matching. This is the behavior KeyVu prefers.
|
|
123
|
+
tank_sequence = details.get("tank_id")
|
|
124
|
+
product_id = None
|
|
125
|
+
product = None
|
|
126
|
+
if not tank_sequence:
|
|
127
|
+
product_id = details.get("product_source_id")
|
|
128
|
+
product = details.get("product_name")
|
|
129
|
+
|
|
130
|
+
return StationDeliveryDetails(
|
|
131
|
+
delivered_volume=details.get("quantity", 0.0),
|
|
132
|
+
volume_unit=UnitSystem.imperial,
|
|
133
|
+
tank_sequence=tank_sequence,
|
|
134
|
+
product_id=product_id,
|
|
135
|
+
product=product,
|
|
136
|
+
is_retained=False # TODO: Support retains
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class StationDeliveryBOLArray(BaseXmlModel):
|
|
141
|
+
bill_of_ladings: Optional[list["StationDeliveryBOL"]] = element(tag="StationDeliveryBillOfLadings")
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class StationDeliveryBOL(BaseXmlModel):
|
|
145
|
+
terminal_name: Optional[str] = element(tag="TerminalName", nillable=True)
|
|
146
|
+
terminal_control_number: str = element(tag="TerminalControlNumber")
|
|
147
|
+
bill_of_lading_number: str = element(tag="BillOfLadingNumber")
|
|
148
|
+
supplier: str = element(tag="Supplier")
|
|
149
|
+
consignee: str = element(tag="Consignee", default="")
|
|
File without changes
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
from functools import lru_cache
|
|
3
|
+
import httpx
|
|
4
|
+
from httpx import Response
|
|
5
|
+
from bb_integrations_lib.provider.api.macropoint.model import LocationUpdateRequest
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class MacropointClient(httpx.AsyncClient):
|
|
9
|
+
def __init__(self, username, password):
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.username = username
|
|
12
|
+
self.password = password
|
|
13
|
+
self._headers = {}
|
|
14
|
+
|
|
15
|
+
@lru_cache(maxsize=1)
|
|
16
|
+
async def _get_token(self):
|
|
17
|
+
encoded = base64.standard_b64encode(f"{self.username}:{self.password}".encode()).decode()
|
|
18
|
+
return f"Basic {encoded}"
|
|
19
|
+
|
|
20
|
+
async def update_location(self, req: LocationUpdateRequest) -> Response:
|
|
21
|
+
return await self.post(
|
|
22
|
+
url="https://macropoint-lite.com/api/1.0/tms/data/location",
|
|
23
|
+
headers={
|
|
24
|
+
"Content-Type": "application/xml",
|
|
25
|
+
"Authorization": await self._get_token(),
|
|
26
|
+
},
|
|
27
|
+
data=req.to_xml()
|
|
28
|
+
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from pydantic_xml import BaseXmlModel, element
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Sender(
|
|
5
|
+
BaseXmlModel,
|
|
6
|
+
):
|
|
7
|
+
load_id: str = element("LoadID")
|
|
8
|
+
|
|
9
|
+
class Requestor(
|
|
10
|
+
BaseXmlModel,
|
|
11
|
+
):
|
|
12
|
+
mpid: str = element("MPID")
|
|
13
|
+
load_id: str = element("LoadID")
|
|
14
|
+
|
|
15
|
+
class AllowAccessFrom(
|
|
16
|
+
BaseXmlModel,
|
|
17
|
+
):
|
|
18
|
+
mpid: str = element("MPID")
|
|
19
|
+
|
|
20
|
+
class Coordinates(
|
|
21
|
+
BaseXmlModel,
|
|
22
|
+
):
|
|
23
|
+
latitude: float = element("Latitude")
|
|
24
|
+
longitude: float = element("Longitude")
|
|
25
|
+
|
|
26
|
+
class Location(
|
|
27
|
+
BaseXmlModel,
|
|
28
|
+
):
|
|
29
|
+
coordinates: Coordinates = element("Coordinates")
|
|
30
|
+
created_date_time: str = element("CreatedDateTime")
|
|
31
|
+
|
|
32
|
+
class LocationUpdateRequest(
|
|
33
|
+
BaseXmlModel,
|
|
34
|
+
tag="TMSLocationData",
|
|
35
|
+
nsmap={"": 'http://macropoint-lite.com/xml/1.0'}
|
|
36
|
+
):
|
|
37
|
+
sender: Sender = element("Sender")
|
|
38
|
+
requestor: Requestor = element("Requestor")
|
|
39
|
+
allow_access_from: AllowAccessFrom = element("AllowAccessFrom")
|
|
40
|
+
location: Location = element("Location")
|
|
File without changes
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
from loguru import logger
|
|
5
|
+
from pydantic import ValidationError
|
|
6
|
+
from bb_integrations_lib.provider.api.pc_miler.model import TokenData
|
|
7
|
+
|
|
8
|
+
route_reports_eagle_standard_params = {
|
|
9
|
+
"ReportRoutes": [
|
|
10
|
+
{
|
|
11
|
+
"ReportingOptions": {
|
|
12
|
+
"UseTollData": True,
|
|
13
|
+
"TollDiscount": "All",
|
|
14
|
+
"IncludeFerryDistance": True,
|
|
15
|
+
"EstimatedTimeOptions": {
|
|
16
|
+
"ETAETD": 1,
|
|
17
|
+
"DateOption": 2,
|
|
18
|
+
"DateAndTime": {
|
|
19
|
+
"DayOfWeek": 4,
|
|
20
|
+
"TimeOfDay": "10:00 AM",
|
|
21
|
+
"TimeZone": 0
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"UseTraffic": True
|
|
25
|
+
},
|
|
26
|
+
"ReportTypes": [
|
|
27
|
+
{
|
|
28
|
+
"__type": "StateReportType:http://pcmiler.alk.com/APIs/v1.0",
|
|
29
|
+
"SortByRoute": False
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"__type": "GeoTunnelReportType:http://pcmiler.alk.com/APIs/v1.0",
|
|
33
|
+
"CiteInterval": 5.0
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"Stops": [
|
|
37
|
+
{
|
|
38
|
+
"Coords": {
|
|
39
|
+
"Lat": "38.36440700",
|
|
40
|
+
"Lon": "-82.60173800"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"Coords": {
|
|
45
|
+
"Lat": "38.08867300",
|
|
46
|
+
"Lon": "-81.83779700"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"Options": {
|
|
51
|
+
"VehicleType": 0,
|
|
52
|
+
"RoutingType": 0,
|
|
53
|
+
"HighwayOnly": False,
|
|
54
|
+
"DistanceUnits": 0,
|
|
55
|
+
"TollRoads": 3,
|
|
56
|
+
"BordersOpen": True,
|
|
57
|
+
"OverrideRestrict": False,
|
|
58
|
+
"HazMatType": 4,
|
|
59
|
+
"RouteOptimization": 0,
|
|
60
|
+
"hubRouting": False,
|
|
61
|
+
"SideOfStreetAdherence": 0,
|
|
62
|
+
"ferryDiscourage": True,
|
|
63
|
+
"AFSetIDs": [-1],
|
|
64
|
+
"UseSites": True
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class PCMilerClient(httpx.AsyncClient):
|
|
72
|
+
def __init__(
|
|
73
|
+
self,
|
|
74
|
+
base_url: str,
|
|
75
|
+
username: str,
|
|
76
|
+
password: str,
|
|
77
|
+
api_key: str,
|
|
78
|
+
timeout: float = 180.0,
|
|
79
|
+
):
|
|
80
|
+
super().__init__(base_url=base_url)
|
|
81
|
+
self.username = username
|
|
82
|
+
self.password = password
|
|
83
|
+
self.api_key = api_key
|
|
84
|
+
self.apis = PCMilerAPIWrapper(client=self)
|
|
85
|
+
self.timeout = httpx.Timeout(timeout, connect=60.0)
|
|
86
|
+
|
|
87
|
+
def __repr__(self):
|
|
88
|
+
return """PC Miler Client designed for PC Miler Web Service"""
|
|
89
|
+
|
|
90
|
+
async def get_token(self, url: str) -> TokenData:
|
|
91
|
+
try:
|
|
92
|
+
json_data = {'apiKey': self.api_key}
|
|
93
|
+
response = await self.post(url, json=json_data)
|
|
94
|
+
response.raise_for_status()
|
|
95
|
+
response_data = response.json()
|
|
96
|
+
return TokenData.model_validate(response_data)
|
|
97
|
+
|
|
98
|
+
except httpx.ReadTimeout as e:
|
|
99
|
+
logger.error(f"Request timed out while getting token: {e}")
|
|
100
|
+
raise
|
|
101
|
+
|
|
102
|
+
except httpx.HTTPStatusError as e:
|
|
103
|
+
status_code = e.response.status_code
|
|
104
|
+
logger.error(f"HTTP error {status_code} while getting token: {e.response.text}")
|
|
105
|
+
raise
|
|
106
|
+
|
|
107
|
+
except httpx.HTTPError as e:
|
|
108
|
+
logger.error(f"HTTP error occurred while getting token: {e}")
|
|
109
|
+
raise
|
|
110
|
+
|
|
111
|
+
except ValidationError as e:
|
|
112
|
+
logger.error(f"Invalid token data received: {e}")
|
|
113
|
+
raise
|
|
114
|
+
|
|
115
|
+
except Exception as e:
|
|
116
|
+
logger.error(f"Unexpected error while getting token: {e}")
|
|
117
|
+
raise
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
class PCMilerAPIWrapper:
|
|
121
|
+
def __init__(self, client: PCMilerClient):
|
|
122
|
+
from bb_integrations_lib.provider.api.pc_miler.web_services_apis import RoutingAPI
|
|
123
|
+
from bb_integrations_lib.provider.api.pc_miler.web_services_apis import SingleSearchAPI
|
|
124
|
+
from bb_integrations_lib.provider.api.pc_miler.web_services_apis import PlacesAPI
|
|
125
|
+
|
|
126
|
+
self.routing = RoutingAPI(client=client)
|
|
127
|
+
self.single_search = SingleSearchAPI(client=client)
|
|
128
|
+
self.places = PlacesAPI(client=client)
|
|
129
|
+
|
|
130
|
+
|