|
| 1 | +from typing import Optional |
| 2 | + |
| 3 | +from ...http_client import HttpClient |
| 4 | +from ...models import Session |
| 5 | + |
| 6 | + |
| 7 | +class LinksSessionClient(HttpClient): |
| 8 | + def __init__(self, **kwargs): |
| 9 | + self._url = "/links/sessions" |
| 10 | + super().__init__(**kwargs) |
| 11 | + |
| 12 | + def create(self): |
| 13 | + return LinksSessionCreate(self) |
| 14 | + |
| 15 | + |
| 16 | +class LinksSessionCreate(object): |
| 17 | + """Auxiliary class to provide methods for session request creation related data.""" |
| 18 | + |
| 19 | + _reference: str |
| 20 | + _success_url: str |
| 21 | + _failure_url: str |
| 22 | + _abandonment_url: str |
| 23 | + _logo_url: Optional[str] |
| 24 | + _primary_color: Optional[str] |
| 25 | + _secondary_color: Optional[str] |
| 26 | + _checkout_display_text: Optional[str] |
| 27 | + _traveller_currency: Optional[str] |
| 28 | + _markup_amount: Optional[str] |
| 29 | + _markup_currency: Optional[str] |
| 30 | + _markup_rate: Optional[str] |
| 31 | + |
| 32 | + def __init__(self, client): |
| 33 | + self._client = client |
| 34 | + self._reference = "" |
| 35 | + self._success_url = "" |
| 36 | + self._failure_url = "" |
| 37 | + self._abandonment_url = "" |
| 38 | + self._logo_url = None |
| 39 | + self._primary_color = None |
| 40 | + self._secondary_color = None |
| 41 | + self._checkout_display_text = None |
| 42 | + self._traveller_currency = None |
| 43 | + self._markup_amount = None |
| 44 | + self._markup_currency = None |
| 45 | + self._markup_rate = None |
| 46 | + |
| 47 | + def reference(self, reference: str): |
| 48 | + """Way to identify the Session. |
| 49 | +
|
| 50 | + This can be a user ID, or similar, and can be |
| 51 | + used to reconcile the Session with your internal systems. |
| 52 | +
|
| 53 | + Example: "user_123" |
| 54 | +
|
| 55 | + """ |
| 56 | + self._reference = reference |
| 57 | + return self |
| 58 | + |
| 59 | + def success_url(self, success_url: str): |
| 60 | + """URL the traveller will be redirected to once an order has been created. |
| 61 | +
|
| 62 | + Where the traveller will end up when their orders has been successfully created |
| 63 | + and they press the 'Return' button. |
| 64 | +
|
| 65 | + Example: "https://example.com/success" |
| 66 | +
|
| 67 | + """ |
| 68 | + self._success_url = success_url |
| 69 | + return self |
| 70 | + |
| 71 | + def failure_url(self, failure_url: str): |
| 72 | + """URL the traveller will be redirected to if there is a failure. |
| 73 | +
|
| 74 | + This is only applicable to a failure that can not be mitigated. |
| 75 | +
|
| 76 | + Example: "https://example.com/failure" |
| 77 | +
|
| 78 | + """ |
| 79 | + self._failure_url = failure_url |
| 80 | + return self |
| 81 | + |
| 82 | + def abandonment_url(self, abandonment_url: str): |
| 83 | + """URL the traveller will be redirected to if they decide to abandon the session. |
| 84 | +
|
| 85 | + This happens when the users presses the 'Return' button. |
| 86 | +
|
| 87 | + Example: "https://example.com/abandonment" |
| 88 | +
|
| 89 | + """ |
| 90 | + self._abandonment_url = abandonment_url |
| 91 | + return self |
| 92 | + |
| 93 | + def logo_url(self, logo_url: str): |
| 94 | + """URL to the logo that will appear at the top-left corner. |
| 95 | +
|
| 96 | + If not provided, Duffel's logo will be used. The logo provided will be resized to |
| 97 | + be 16 pixels high, to ensure it fits the header. The aspect ratio will be |
| 98 | + maintained, ensuring it won't look squashed or have misproportioned. |
| 99 | +
|
| 100 | + Example: "https://example.com/logo.svg" |
| 101 | +
|
| 102 | + """ |
| 103 | + self._logo_url = logo_url |
| 104 | + return self |
| 105 | + |
| 106 | + def primary_color(self, primary_color: str): |
| 107 | + """Primary colour that will be used to customise the session. |
| 108 | +
|
| 109 | + It should be an hexadecimal CSS-compatible colour. If one is not provided the |
| 110 | + default Duffel colour will be used. |
| 111 | +
|
| 112 | + Example: "#000000" |
| 113 | +
|
| 114 | + """ |
| 115 | + self._primary_color = primary_color |
| 116 | + return self |
| 117 | + |
| 118 | + def secondary_color(self, secondary_color: str): |
| 119 | + """Secondary colour that will be used to customise the session. |
| 120 | +
|
| 121 | + It should be an hexadecimal CSS-compatible colour. If one is not provided the |
| 122 | + default Duffel colour will be used. |
| 123 | +
|
| 124 | + Example: "#000000" |
| 125 | +
|
| 126 | + """ |
| 127 | + self._secondary_color = secondary_color |
| 128 | + return self |
| 129 | + |
| 130 | + def checkout_display_text(self, checkout_display_text: str): |
| 131 | + """Text that will appear at the bottom of the checkout form. |
| 132 | +
|
| 133 | + If not provided nothing will be displayed. |
| 134 | +
|
| 135 | + Example: "Thank you for booking with us." |
| 136 | +
|
| 137 | + """ |
| 138 | + self._checkout_display_text = checkout_display_text |
| 139 | + return self |
| 140 | + |
| 141 | + def traveller_currency(self, traveller_currency: str): |
| 142 | + """The currency in which the traveller will see prices and pay in. If not provided |
| 143 | + it will default to the settlement currency of your account. The traveller will be |
| 144 | + able to change this currency before searching. |
| 145 | +
|
| 146 | + Example: "GBP" |
| 147 | +
|
| 148 | + """ |
| 149 | + self._traveller_currency = traveller_currency |
| 150 | + return self |
| 151 | + |
| 152 | + def markup_amount(self, markup_amount: str): |
| 153 | + """The absolute amount that will be added to the final price to be paid by the |
| 154 | + traveller. If not provided it will default to zero. This field is required if |
| 155 | + markup_currency is provided. |
| 156 | +
|
| 157 | + Example: "1.00" |
| 158 | +
|
| 159 | + """ |
| 160 | + self._markup_amount = markup_amount |
| 161 | + return self |
| 162 | + |
| 163 | + def markup_currency(self, markup_currency: str): |
| 164 | + """The currency of the markup_amount. It should always match the settlement |
| 165 | + currency of the organisation. This field is required if markup_amount is provided. |
| 166 | +
|
| 167 | + Example: "GBP" |
| 168 | +
|
| 169 | + """ |
| 170 | + self._markup_currency = markup_currency |
| 171 | + return self |
| 172 | + |
| 173 | + def markup_rate(self, markup_rate: str): |
| 174 | + """The rate that will be applied to the total amount to be paid by the |
| 175 | + traveller. For a 1% markup provide 0.01 as the markup_rate. If not provided it |
| 176 | + will default to zero. |
| 177 | +
|
| 178 | + Example: "0.01" |
| 179 | +
|
| 180 | + """ |
| 181 | + self._markup_rate = markup_rate |
| 182 | + return self |
| 183 | + |
| 184 | + class InvalidMandatoryFields(Exception): |
| 185 | + """Fields 'reference', 'success_url', 'failure_url', and 'abandonment_url' are |
| 186 | + mandatory""" |
| 187 | + |
| 188 | + class InvalidMarkup(Exception): |
| 189 | + """Both fields 'markup_amount' and 'markup_currency' have to exist or not at all |
| 190 | + but it is not possible to have one and not the other""" |
| 191 | + |
| 192 | + def _validate_mandatory(self): |
| 193 | + if ( |
| 194 | + self._reference == "" |
| 195 | + or self._success_url == "" |
| 196 | + or self._failure_url == "" |
| 197 | + or self._abandonment_url == "" |
| 198 | + ): |
| 199 | + raise LinksSessionCreate.InvalidMandatoryFields |
| 200 | + |
| 201 | + def _validate_markup(self): |
| 202 | + if (self._markup_currency is None and self._markup_amount is not None) or ( |
| 203 | + self._markup_currency is not None and self._markup_amount is None |
| 204 | + ): |
| 205 | + raise LinksSessionCreate.InvalidMarkup |
| 206 | + |
| 207 | + def execute(self): |
| 208 | + """POST /links/sessions - trigger the call to create the session""" |
| 209 | + self._validate_mandatory() |
| 210 | + |
| 211 | + body_data = { |
| 212 | + "reference": self._reference, |
| 213 | + "success_url": self._success_url, |
| 214 | + "failure_url": self._failure_url, |
| 215 | + "abandonment_url": self._abandonment_url, |
| 216 | + } |
| 217 | + |
| 218 | + if self._logo_url: |
| 219 | + body_data["logo_url"] = self._logo_url |
| 220 | + if self._primary_color: |
| 221 | + body_data["primary_color"] = self._primary_color |
| 222 | + if self._secondary_color: |
| 223 | + body_data["secondary_color"] = self._secondary_color |
| 224 | + if self._checkout_display_text: |
| 225 | + body_data["checkout_display_text"] = self._checkout_display_text |
| 226 | + if self._traveller_currency: |
| 227 | + body_data["traveller_currency"] = self._traveller_currency |
| 228 | + if self._markup_rate: |
| 229 | + body_data["markup_rate"] = self._markup_rate |
| 230 | + if self._markup_currency and self._markup_amount: |
| 231 | + body_data["markup_currency"] = self._markup_currency |
| 232 | + body_data["markup_amount"] = self._markup_amount |
| 233 | + else: |
| 234 | + self._validate_markup() |
| 235 | + |
| 236 | + res = self._client.do_post(self._client._url, body={"data": body_data}) |
| 237 | + return Session.from_json(res["data"]) |
0 commit comments