Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
is_hub=False,
options=units.ShippingOption,
services=units.ShippingService,
service_levels=units.DEFAULT_SERVICES,
connection_configs=units.ConnectionConfig,
# Extra info
website="https://www.post.at",
Expand Down
36 changes: 22 additions & 14 deletions modules/connectors/postat/karrio/providers/postat/error.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,26 @@ def parse_error_response(
**kwargs,
) -> typing.List[models.Message]:
"""Parse error response from PostAT SOAP API."""
errors = lib.find_element("Error", response) or []
messages: typing.List[models.Message] = []

return [
models.Message(
carrier_id=settings.carrier_id,
carrier_name=settings.carrier_name,
code=error.findtext("Code") or "ERROR",
message=error.findtext("Message") or "",
details={
**({"description": error.findtext("Description")} if error.findtext("Description") else {}),
**kwargs,
},
)
for error in errors
] + extract_fault(response, settings)
# Extract SOAP faults (standard SOAP error handling)
messages.extend(extract_fault(response, settings))

# Parse PostAT errorMessage element (main error field in responses)
error_messages = lib.find_element("errorMessage", response) or []
for err_elem in error_messages:
if err_elem.text and err_elem.text.strip():
msg_text = err_elem.text.strip()
# Avoid duplicates
if not any(msg_text in (m.message or "") for m in messages):
messages.append(
models.Message(
carrier_id=settings.carrier_id,
carrier_name=settings.carrier_name,
code="POSTAT_ERROR",
message=msg_text,
details=kwargs if kwargs else None,
)
)

return messages
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,19 @@ def shipment_cancel_request(
) -> lib.Serializable:
"""Create a shipment cancellation request for the PostAT SOAP API."""
# Build request using generated schema types
request = lib.Envelope(
Body=lib.Body(
postat_void.VoidShipmentType(
row=[
postat_void.VoidShipmentRowType(
TrackingNumber=payload.shipment_identifier,
OrgUnitID=settings.org_unit_id,
OrgUnitGuid=settings.org_unit_guid,
)
]
void_shipment = postat_void.VoidShipmentType(
row=[
postat_void.VoidShipmentRowType(
TrackingNumber=payload.shipment_identifier,
OrgUnitID=settings.org_unit_id,
OrgUnitGuid=settings.org_unit_guid,
)
)
]
)
# Set proper element name for PostAT API (VoidShipment, not VoidShipmentType)
void_shipment.original_tagname_ = "VoidShipment"

request = lib.Envelope(Body=lib.Body(void_shipment))

return lib.Serializable(request, lib.envelope_serializer)
return lib.Serializable(request, provider_utils.standard_request_serializer)

119 changes: 62 additions & 57 deletions modules/connectors/postat/karrio/providers/postat/shipment/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,14 @@ def parse_shipment_response(
response = _response.deserialize()
messages = error.parse_error_response(response, settings)
result = lib.find_element("ImportShipmentResult", response, first=True)

# Check if we have valid tracking codes before extracting
code_elements = lib.find_element("Code", result) if result is not None else []
has_tracking = any(code.text for code in (code_elements or []))

shipment = (
_extract_details(response, settings)
if result is not None and not any(messages)
if result is not None and has_tracking and not any(messages)
else None
)

Expand Down Expand Up @@ -86,62 +91,62 @@ def shipment_request(
)

# Build request using generated schema types
request = lib.Envelope(
Body=lib.Body(
postat.ImportShipmentType(
row=[
postat.ImportShipmentRowType(
ClientID=settings.client_id,
OrgUnitID=settings.org_unit_id,
OrgUnitGuid=settings.org_unit_guid,
DeliveryServiceThirdPartyID=service,
CustomDataBit1=False,
OUShipperReference1=payload.reference,
ColloList=postat.ColloListType(
ColloRow=[
postat.ColloRowType(
Weight=package.weight.KG,
Length=package.length.CM,
Width=package.width.CM,
Height=package.height.CM,
)
for package in packages
]
),
OURecipientAddress=postat.AddressType(
Name1=recipient.company_name or recipient.person_name,
Name2=(
recipient.person_name
if recipient.company_name
else None
),
AddressLine1=recipient.street,
AddressLine2=recipient.address_line2,
HouseNumber=recipient.street_number,
PostalCode=recipient.postal_code,
City=recipient.city,
CountryID=recipient.country_code,
Email=recipient.email,
Tel1=recipient.phone_number,
),
OUShipperAddress=postat.AddressType(
Name1=shipper.company_name or shipper.person_name,
Name2=shipper.person_name if shipper.company_name else None,
AddressLine1=shipper.street,
AddressLine2=shipper.address_line2,
PostalCode=shipper.postal_code,
City=shipper.city,
CountryID=shipper.country_code,
),
PrinterObject=postat.PrinterObjectType(
LabelFormatID=label_size,
LanguageID=label_format,
PaperLayoutID=paper_layout,
),
)
]
import_shipment = postat.ImportShipmentType(
row=[
postat.ImportShipmentRowType(
ClientID=settings.client_id,
OrgUnitID=settings.org_unit_id,
OrgUnitGuid=settings.org_unit_guid,
DeliveryServiceThirdPartyID=service,
CustomDataBit1=False,
OUShipperReference1=payload.reference,
ColloList=postat.ColloListType(
ColloRow=[
postat.ColloRowType(
Weight=package.weight.KG,
Length=package.length.CM,
Width=package.width.CM,
Height=package.height.CM,
)
for package in packages
]
),
OURecipientAddress=postat.AddressType(
Name1=recipient.company_name or recipient.person_name,
Name2=(
recipient.person_name
if recipient.company_name
else None
),
AddressLine1=recipient.street,
AddressLine2=recipient.address_line2,
HouseNumber=recipient.street_number,
PostalCode=recipient.postal_code,
City=recipient.city,
CountryID=recipient.country_code,
Email=recipient.email,
Tel1=recipient.phone_number,
),
OUShipperAddress=postat.AddressType(
Name1=shipper.company_name or shipper.person_name,
Name2=shipper.person_name if shipper.company_name else None,
AddressLine1=shipper.street,
AddressLine2=shipper.address_line2,
PostalCode=shipper.postal_code,
City=shipper.city,
CountryID=shipper.country_code,
),
PrinterObject=postat.PrinterObjectType(
LabelFormatID=label_size,
LanguageID=label_format,
PaperLayoutID=paper_layout,
),
)
)
]
)
# Set proper element name for PostAT API (ImportShipment, not ImportShipmentType)
import_shipment.original_tagname_ = "ImportShipment"

request = lib.Envelope(Body=lib.Body(import_shipment))

return lib.Serializable(request, lib.envelope_serializer)
return lib.Serializable(request, provider_utils.standard_request_serializer)
20 changes: 19 additions & 1 deletion modules/connectors/postat/karrio/providers/postat/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@
import attr
import karrio.lib as lib
import karrio.core as core
import karrio.core.utils as utils
from karrio.core.utils.soap import apply_namespaceprefix


def standard_request_serializer(envelope: lib.Envelope) -> str:
"""Serialize envelope to PostAT SOAP format with proper namespaces."""
namespace_def = (
'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" '
'xmlns:post="http://post.ondot.at"'
)

envelope.ns_prefix_ = "soapenv"
envelope.Body.ns_prefix_ = "soapenv"

for node in envelope.Body.anytypeobjs_:
apply_namespaceprefix(node, "post")

return utils.XP.export(envelope, namespacedef_=namespace_def)


@attr.s(auto_attribs=True)
Expand Down Expand Up @@ -35,7 +53,7 @@ def server_url(self):
"""
return (
self.connection_config.server_url.state
or "https://plc.post.at/Post.Webservice/ShippingService.svc"
or "https://plc.post.at/Post.Webservice/ShippingService.svc/secure"
)

@property
Expand Down
3 changes: 1 addition & 2 deletions modules/connectors/postat/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@

from postat.test_shipment import *
from tests.postat.test_shipment import *
2 changes: 1 addition & 1 deletion modules/core/karrio/server/core/dataunits.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def _get_generic_carriers():
for s in c.services
or [
lib.to_object(lib.models.ServiceLevel, _)
for _ in references["service_levels"][c.ext]
for _ in references.get("service_levels", {}).get(c.ext, [])
]
}
for c in custom_carriers
Expand Down
Loading