karrio-postat 2026.1.4__py3-none-any.whl → 2026.1.5__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.
@@ -21,6 +21,7 @@ METADATA = PluginMetadata(
21
21
  is_hub=False,
22
22
  options=units.ShippingOption,
23
23
  services=units.ShippingService,
24
+ service_levels=units.DEFAULT_SERVICES,
24
25
  connection_configs=units.ConnectionConfig,
25
26
  # Extra info
26
27
  website="https://www.post.at",
@@ -13,18 +13,26 @@ def parse_error_response(
13
13
  **kwargs,
14
14
  ) -> typing.List[models.Message]:
15
15
  """Parse error response from PostAT SOAP API."""
16
- errors = lib.find_element("Error", response) or []
16
+ messages: typing.List[models.Message] = []
17
17
 
18
- return [
19
- models.Message(
20
- carrier_id=settings.carrier_id,
21
- carrier_name=settings.carrier_name,
22
- code=error.findtext("Code") or "ERROR",
23
- message=error.findtext("Message") or "",
24
- details={
25
- **({"description": error.findtext("Description")} if error.findtext("Description") else {}),
26
- **kwargs,
27
- },
28
- )
29
- for error in errors
30
- ] + extract_fault(response, settings)
18
+ # Extract SOAP faults (standard SOAP error handling)
19
+ messages.extend(extract_fault(response, settings))
20
+
21
+ # Parse PostAT errorMessage element (main error field in responses)
22
+ error_messages = lib.find_element("errorMessage", response) or []
23
+ for err_elem in error_messages:
24
+ if err_elem.text and err_elem.text.strip():
25
+ msg_text = err_elem.text.strip()
26
+ # Avoid duplicates
27
+ if not any(msg_text in (m.message or "") for m in messages):
28
+ messages.append(
29
+ models.Message(
30
+ carrier_id=settings.carrier_id,
31
+ carrier_name=settings.carrier_name,
32
+ code="POSTAT_ERROR",
33
+ message=msg_text,
34
+ details=kwargs if kwargs else None,
35
+ )
36
+ )
37
+
38
+ return messages
@@ -47,19 +47,19 @@ def shipment_cancel_request(
47
47
  ) -> lib.Serializable:
48
48
  """Create a shipment cancellation request for the PostAT SOAP API."""
49
49
  # Build request using generated schema types
50
- request = lib.Envelope(
51
- Body=lib.Body(
52
- postat_void.VoidShipmentType(
53
- row=[
54
- postat_void.VoidShipmentRowType(
55
- TrackingNumber=payload.shipment_identifier,
56
- OrgUnitID=settings.org_unit_id,
57
- OrgUnitGuid=settings.org_unit_guid,
58
- )
59
- ]
50
+ void_shipment = postat_void.VoidShipmentType(
51
+ row=[
52
+ postat_void.VoidShipmentRowType(
53
+ TrackingNumber=payload.shipment_identifier,
54
+ OrgUnitID=settings.org_unit_id,
55
+ OrgUnitGuid=settings.org_unit_guid,
60
56
  )
61
- )
57
+ ]
62
58
  )
59
+ # Set proper element name for PostAT API (VoidShipment, not VoidShipmentType)
60
+ void_shipment.original_tagname_ = "VoidShipment"
61
+
62
+ request = lib.Envelope(Body=lib.Body(void_shipment))
63
63
 
64
- return lib.Serializable(request, lib.envelope_serializer)
64
+ return lib.Serializable(request, provider_utils.standard_request_serializer)
65
65
 
@@ -17,9 +17,14 @@ def parse_shipment_response(
17
17
  response = _response.deserialize()
18
18
  messages = error.parse_error_response(response, settings)
19
19
  result = lib.find_element("ImportShipmentResult", response, first=True)
20
+
21
+ # Check if we have valid tracking codes before extracting
22
+ code_elements = lib.find_element("Code", result) if result is not None else []
23
+ has_tracking = any(code.text for code in (code_elements or []))
24
+
20
25
  shipment = (
21
26
  _extract_details(response, settings)
22
- if result is not None and not any(messages)
27
+ if result is not None and has_tracking and not any(messages)
23
28
  else None
24
29
  )
25
30
 
@@ -86,62 +91,62 @@ def shipment_request(
86
91
  )
87
92
 
88
93
  # Build request using generated schema types
89
- request = lib.Envelope(
90
- Body=lib.Body(
91
- postat.ImportShipmentType(
92
- row=[
93
- postat.ImportShipmentRowType(
94
- ClientID=settings.client_id,
95
- OrgUnitID=settings.org_unit_id,
96
- OrgUnitGuid=settings.org_unit_guid,
97
- DeliveryServiceThirdPartyID=service,
98
- CustomDataBit1=False,
99
- OUShipperReference1=payload.reference,
100
- ColloList=postat.ColloListType(
101
- ColloRow=[
102
- postat.ColloRowType(
103
- Weight=package.weight.KG,
104
- Length=package.length.CM,
105
- Width=package.width.CM,
106
- Height=package.height.CM,
107
- )
108
- for package in packages
109
- ]
110
- ),
111
- OURecipientAddress=postat.AddressType(
112
- Name1=recipient.company_name or recipient.person_name,
113
- Name2=(
114
- recipient.person_name
115
- if recipient.company_name
116
- else None
117
- ),
118
- AddressLine1=recipient.street,
119
- AddressLine2=recipient.address_line2,
120
- HouseNumber=recipient.street_number,
121
- PostalCode=recipient.postal_code,
122
- City=recipient.city,
123
- CountryID=recipient.country_code,
124
- Email=recipient.email,
125
- Tel1=recipient.phone_number,
126
- ),
127
- OUShipperAddress=postat.AddressType(
128
- Name1=shipper.company_name or shipper.person_name,
129
- Name2=shipper.person_name if shipper.company_name else None,
130
- AddressLine1=shipper.street,
131
- AddressLine2=shipper.address_line2,
132
- PostalCode=shipper.postal_code,
133
- City=shipper.city,
134
- CountryID=shipper.country_code,
135
- ),
136
- PrinterObject=postat.PrinterObjectType(
137
- LabelFormatID=label_size,
138
- LanguageID=label_format,
139
- PaperLayoutID=paper_layout,
140
- ),
141
- )
142
- ]
94
+ import_shipment = postat.ImportShipmentType(
95
+ row=[
96
+ postat.ImportShipmentRowType(
97
+ ClientID=settings.client_id,
98
+ OrgUnitID=settings.org_unit_id,
99
+ OrgUnitGuid=settings.org_unit_guid,
100
+ DeliveryServiceThirdPartyID=service,
101
+ CustomDataBit1=False,
102
+ OUShipperReference1=payload.reference,
103
+ ColloList=postat.ColloListType(
104
+ ColloRow=[
105
+ postat.ColloRowType(
106
+ Weight=package.weight.KG,
107
+ Length=package.length.CM,
108
+ Width=package.width.CM,
109
+ Height=package.height.CM,
110
+ )
111
+ for package in packages
112
+ ]
113
+ ),
114
+ OURecipientAddress=postat.AddressType(
115
+ Name1=recipient.company_name or recipient.person_name,
116
+ Name2=(
117
+ recipient.person_name
118
+ if recipient.company_name
119
+ else None
120
+ ),
121
+ AddressLine1=recipient.street,
122
+ AddressLine2=recipient.address_line2,
123
+ HouseNumber=recipient.street_number,
124
+ PostalCode=recipient.postal_code,
125
+ City=recipient.city,
126
+ CountryID=recipient.country_code,
127
+ Email=recipient.email,
128
+ Tel1=recipient.phone_number,
129
+ ),
130
+ OUShipperAddress=postat.AddressType(
131
+ Name1=shipper.company_name or shipper.person_name,
132
+ Name2=shipper.person_name if shipper.company_name else None,
133
+ AddressLine1=shipper.street,
134
+ AddressLine2=shipper.address_line2,
135
+ PostalCode=shipper.postal_code,
136
+ City=shipper.city,
137
+ CountryID=shipper.country_code,
138
+ ),
139
+ PrinterObject=postat.PrinterObjectType(
140
+ LabelFormatID=label_size,
141
+ LanguageID=label_format,
142
+ PaperLayoutID=paper_layout,
143
+ ),
143
144
  )
144
- )
145
+ ]
145
146
  )
147
+ # Set proper element name for PostAT API (ImportShipment, not ImportShipmentType)
148
+ import_shipment.original_tagname_ = "ImportShipment"
149
+
150
+ request = lib.Envelope(Body=lib.Body(import_shipment))
146
151
 
147
- return lib.Serializable(request, lib.envelope_serializer)
152
+ return lib.Serializable(request, provider_utils.standard_request_serializer)
@@ -226,6 +226,8 @@ def load_services_from_csv() -> list:
226
226
  zone = models.ServiceZone(
227
227
  label=row.get("zone_label", "Default Zone"),
228
228
  rate=float(row.get("rate", 0.0)),
229
+ min_weight=float(row["min_weight"]) if row.get("min_weight") else None,
230
+ max_weight=float(row["max_weight"]) if row.get("max_weight") else None,
229
231
  transit_days=transit_days,
230
232
  country_codes=country_codes if country_codes else None,
231
233
  )
@@ -3,6 +3,24 @@
3
3
  import attr
4
4
  import karrio.lib as lib
5
5
  import karrio.core as core
6
+ import karrio.core.utils as utils
7
+ from karrio.core.utils.soap import apply_namespaceprefix
8
+
9
+
10
+ def standard_request_serializer(envelope: lib.Envelope) -> str:
11
+ """Serialize envelope to PostAT SOAP format with proper namespaces."""
12
+ namespace_def = (
13
+ 'xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" '
14
+ 'xmlns:post="http://post.ondot.at"'
15
+ )
16
+
17
+ envelope.ns_prefix_ = "soapenv"
18
+ envelope.Body.ns_prefix_ = "soapenv"
19
+
20
+ for node in envelope.Body.anytypeobjs_:
21
+ apply_namespaceprefix(node, "post")
22
+
23
+ return utils.XP.export(envelope, namespacedef_=namespace_def)
6
24
 
7
25
 
8
26
  @attr.s(auto_attribs=True)
@@ -35,7 +53,7 @@ class Settings(core.Settings):
35
53
  """
36
54
  return (
37
55
  self.connection_config.server_url.state
38
- or "https://plc.post.at/Post.Webservice/ShippingService.svc"
56
+ or "https://plc.post.at/Post.Webservice/ShippingService.svc/secure"
39
57
  )
40
58
 
41
59
  @property
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: karrio_postat
3
- Version: 2026.1.4
3
+ Version: 2026.1.5
4
4
  Summary: Karrio - Austrian Post Shipping Extension
5
5
  Author-email: karrio <hello@karrio.io>
6
6
  License-Expression: LGPL-3.0
@@ -2,19 +2,19 @@ karrio/mappers/postat/__init__.py,sha256=c12wXYUbeqRwfHWCaApOehQEaAn6y58dnzizXn0
2
2
  karrio/mappers/postat/mapper.py,sha256=meokZ91UDJjuzBfK6u0Wz31lFuoD4K5pVmS9HpY-tz8,1630
3
3
  karrio/mappers/postat/proxy.py,sha256=B5pIX2Q-uQJhZjZlJtNIwxbn51p_7Bp-QlEOGuC97Zw,1611
4
4
  karrio/mappers/postat/settings.py,sha256=JkF6yO-sgpp6zQ7JbBjAZTf50U1l02ukQMSnaCjqm74,1094
5
- karrio/plugins/postat/__init__.py,sha256=PyMADJCQTU01xcxRIwQM4-ECdKD2kzbxXJcar81DiOI,1011
5
+ karrio/plugins/postat/__init__.py,sha256=NQ3aEHSWDWoExGOadQ7ryxDH6Tu5KMhY5QJEyRuHSeg,1054
6
6
  karrio/providers/postat/__init__.py,sha256=4hksVX0z3YuFqljwLnrMpwcCaS1k-F6vXXnrhcR7w6Y,254
7
- karrio/providers/postat/error.py,sha256=uPrthPtL-VCb9H_7-Ob2KJZsmrB-Jns7j1WTkskQjhE,951
8
- karrio/providers/postat/units.py,sha256=fReSTwqZbhIloVwkeROrI4l9KjMgLGeWWYyZz7Lpd74,7726
9
- karrio/providers/postat/utils.py,sha256=ee-O4It-Lb4VBoB4mk-85C9pnYCicsfzpGYdmwemU9s,1439
7
+ karrio/providers/postat/error.py,sha256=ROKPQ2vKSkErkQxV3DxWsrKU1lNAAVOHh29zlea2BXE,1342
8
+ karrio/providers/postat/units.py,sha256=7ZDANxMPJwIuLN3FNliBspuPTtanf84z27Clvvdxy1k,7902
9
+ karrio/providers/postat/utils.py,sha256=_920vcSPcjQ-xHwZQbn_CoXG21l9Lq2v3GKhbl3Wh2g,2053
10
10
  karrio/providers/postat/shipment/__init__.py,sha256=LBFK83E-DV24daViy0wFQWQGYPTSe5XvGillDp2LsZg,229
11
- karrio/providers/postat/shipment/cancel.py,sha256=VHT7YcB4S-2HNtKhMlch8_3V_Ex5MkJCvqjLXSyzCm0,2080
12
- karrio/providers/postat/shipment/create.py,sha256=2vi_vf3UnTSxxOTOKwvEnsfIETAcuctghIDqc706MM0,5936
11
+ karrio/providers/postat/shipment/cancel.py,sha256=OdfL7DvnmidhHFXm7XKvdIRlYlDQjpU2BnsWk0MPEE0,2169
12
+ karrio/providers/postat/shipment/create.py,sha256=P_W0tOAJkwbXyRVFP95sYtMxPkihdAA-m2vV7SCOO6w,5917
13
13
  karrio/schemas/postat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  karrio/schemas/postat/plc_types.py,sha256=VmqXCsiptEf2Iv48zzlal4mjd2kEmG8oCK-CTDHYHO8,155450
15
15
  karrio/schemas/postat/void_types.py,sha256=49lZwTbVudeRiwXofLneZv8ykuJN449Q1vA7SpO1yeU,71559
16
- karrio_postat-2026.1.4.dist-info/METADATA,sha256=L3g2dtpC21HwEy7Ej33dL-efsFeysMZ8MXiCxftfEzY,1006
17
- karrio_postat-2026.1.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
18
- karrio_postat-2026.1.4.dist-info/entry_points.txt,sha256=-oCWdqyDuP9WWI6-l-QkY8RyPTdQdOs458D6T8adp_I,57
19
- karrio_postat-2026.1.4.dist-info/top_level.txt,sha256=9Nasa6abG7pPPG8MGzlemnqw1ohIqgouzQ7HGBnOFLg,27
20
- karrio_postat-2026.1.4.dist-info/RECORD,,
16
+ karrio_postat-2026.1.5.dist-info/METADATA,sha256=CaA4fko-65JiwA3ygB4Kb9cbquOubhs2E4KLvNRAJGM,1006
17
+ karrio_postat-2026.1.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
18
+ karrio_postat-2026.1.5.dist-info/entry_points.txt,sha256=-oCWdqyDuP9WWI6-l-QkY8RyPTdQdOs458D6T8adp_I,57
19
+ karrio_postat-2026.1.5.dist-info/top_level.txt,sha256=9Nasa6abG7pPPG8MGzlemnqw1ohIqgouzQ7HGBnOFLg,27
20
+ karrio_postat-2026.1.5.dist-info/RECORD,,