amazon-orders 2.0.0__tar.gz → 2.0.2__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.
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/CHANGELOG.md +39 -19
- {amazon_orders-2.0.0/amazon_orders.egg-info → amazon_orders-2.0.2}/PKG-INFO +4 -4
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/README.md +3 -3
- {amazon_orders-2.0.0 → amazon_orders-2.0.2/amazon_orders.egg-info}/PKG-INFO +4 -4
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/__init__.py +1 -1
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/cli.py +5 -1
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/conf.py +3 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/entity/order.py +19 -28
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/entity/shipment.py +6 -1
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/orders.py +7 -1
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/selectors.py +2 -2
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/tests/test_conf.py +1 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/tests/test_orders.py +6 -1
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/tests/testcase.py +10 -7
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/LICENSE +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/MANIFEST.in +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazon_orders.egg-info/SOURCES.txt +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazon_orders.egg-info/dependency_links.txt +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazon_orders.egg-info/entry_points.txt +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazon_orders.egg-info/requires.txt +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazon_orders.egg-info/top_level.txt +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/banner.txt +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/constants.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/entity/__init__.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/entity/item.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/entity/parsable.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/entity/recipient.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/entity/seller.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/exception.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/forms.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/session.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/amazonorders/util.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/pyproject.toml +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/setup.cfg +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/tests/test_cli.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/tests/test_session.py +0 -0
- {amazon_orders-2.0.0 → amazon_orders-2.0.2}/tests/test_util.py +0 -0
|
@@ -4,7 +4,27 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
-
## [Unreleased](https://github.com/alexdlaird/amazon-orders/compare/2.0.
|
|
7
|
+
## [Unreleased](https://github.com/alexdlaird/amazon-orders/compare/2.0.2...HEAD)
|
|
8
|
+
|
|
9
|
+
## [2.0.2](https://github.com/alexdlaird/amazon-orders/compare/2.0.1...2.0.2) - 2024-10-30
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `item_class` to the config file, which allows for overriding the `Item` class.
|
|
14
|
+
- Support for Amazon's new `data-component` tag on order subtotals.
|
|
15
|
+
- Build and stability improvements.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- The return value of `Order._parse_recipient()` is now optional, so parsing doesn't break digital goods without a shipping address.
|
|
20
|
+
- Redundant order ID logic to parse from the URI, simplified to consistently fetch from page.
|
|
21
|
+
- Support for order details selector on Amazon's legacy digital orders page.
|
|
22
|
+
|
|
23
|
+
## [2.0.1](https://github.com/alexdlaird/amazon-orders/compare/2.0.0...2.0.1) - 2024-10-27
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
|
|
27
|
+
Build and stability improvements.
|
|
8
28
|
|
|
9
29
|
## [2.0.0](https://github.com/alexdlaird/amazon-orders/compare/1.1.4...2.0.0) - 2024-10-26
|
|
10
30
|
|
|
@@ -18,11 +38,11 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
18
38
|
|
|
19
39
|
### Changed
|
|
20
40
|
|
|
21
|
-
- Removed global constants in `amazonorders.constants`. Now `amazonorders.constants.Constants` and `amazonorders.selectors.Selectors` classes are used, can be overridden with `constants_class` and `selectors_class` in the config file.
|
|
41
|
+
- Removed global constants in `amazonorders.constants`. Now [`amazonorders.constants.Constants`](https://amazon-orders.readthedocs.io/api.html#amazonorders.constants.Constants) and [`amazonorders.selectors.Selectors`](https://amazon-orders.readthedocs.io/api.html#amazonorders.selectors.Selectors) classes are used, can be overridden with `constants_class` and `selectors_class` in the config file.
|
|
22
42
|
|
|
23
43
|
### Removed
|
|
24
44
|
|
|
25
|
-
- `session.AUTH_FORMS`. Pass `auth_forms` when instantiating `AmazonSession` instead.
|
|
45
|
+
- `session.AUTH_FORMS`. Pass [`auth_forms` when instantiating `AmazonSession`](https://amazon-orders.readthedocs.io/api.html#amazonorders.session.AmazonSession) instead.
|
|
26
46
|
|
|
27
47
|
## [1.1.4](https://github.com/alexdlaird/amazon-orders/compare/1.1.3...1.1.4) - 2024-06-07
|
|
28
48
|
|
|
@@ -58,9 +78,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
58
78
|
|
|
59
79
|
### Changed
|
|
60
80
|
|
|
61
|
-
- [AmazonOrder.debug](https://amazon-orders.readthedocs.io/
|
|
81
|
+
- [AmazonOrder.debug](https://amazon-orders.readthedocs.io/api.html#amazonorders.orders.AmazonOrders.debug)
|
|
62
82
|
defaults to the value
|
|
63
|
-
of [AmazonSession.debug](https://amazon-orders.readthedocs.io/
|
|
83
|
+
of [AmazonSession.debug](https://amazon-orders.readthedocs.io/api.html#amazonorders.session.AmazonSession.debug)
|
|
64
84
|
if an override is not passed.
|
|
65
85
|
|
|
66
86
|
## [1.1.1](https://github.com/alexdlaird/amazon-orders/compare/1.0.16...1.1.1) - 2024-04-09
|
|
@@ -145,12 +165,12 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
145
165
|
|
|
146
166
|
### Added
|
|
147
167
|
|
|
148
|
-
- [AuthForm](https://amazon-orders.readthedocs.io/
|
|
168
|
+
- [AuthForm](https://amazon-orders.readthedocs.io/api.html#amazonorders.forms.AuthForm)'s now
|
|
149
169
|
passes `captcha_img_url` to its `prompt()` fallback for Captcha, useful for
|
|
150
|
-
overriding [IODefault](https://amazon-orders.readthedocs.io/
|
|
151
|
-
- [MfaDeviceSelectForm](https://amazon-orders.readthedocs.io/
|
|
170
|
+
overriding [IODefault](https://amazon-orders.readthedocs.io/api.html#amazonorders.session.IODefault).
|
|
171
|
+
- [MfaDeviceSelectForm](https://amazon-orders.readthedocs.io/api.html#amazonorders.forms.MfaDeviceSelectForm)
|
|
152
172
|
now passes `mfa_device_select_choices` to `prompt()`, useful for
|
|
153
|
-
overrides [IODefault](https://amazon-orders.readthedocs.io/
|
|
173
|
+
overrides [IODefault](https://amazon-orders.readthedocs.io/api.html#amazonorders.session.IODefault).
|
|
154
174
|
- Documentation improvements.
|
|
155
175
|
|
|
156
176
|
## [1.0.8](https://github.com/alexdlaird/amazon-orders/compare/1.0.7...1.0.8) - 2024-01-30
|
|
@@ -163,9 +183,9 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
163
183
|
|
|
164
184
|
### Added
|
|
165
185
|
|
|
166
|
-
- [AuthForm](https://amazon-orders.readthedocs.io/
|
|
186
|
+
- [AuthForm](https://amazon-orders.readthedocs.io/api.html#amazonorders.forms.AuthForm) abstract class, and
|
|
167
187
|
migrated all auth flow items to subclasses of this class.
|
|
168
|
-
- [Parsable.simple_parse()](https://amazon-orders.readthedocs.io/
|
|
188
|
+
- [Parsable.simple_parse()](https://amazon-orders.readthedocs.io/api.html#amazonorders.entities.parsable.Parsable.simple_parse),
|
|
169
189
|
which can handle most basic fields when parised with CSS selectors.
|
|
170
190
|
- Stability improvements.
|
|
171
191
|
- Test improvements.
|
|
@@ -192,17 +212,17 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
192
212
|
|
|
193
213
|
### Added
|
|
194
214
|
|
|
195
|
-
- [Item.image_link](https://amazon-orders.readthedocs.io/
|
|
196
|
-
- [Item.quantity](https://amazon-orders.readthedocs.io/
|
|
215
|
+
- [Item.image_link](https://amazon-orders.readthedocs.io/api.html#amazonorders.entity.item.Item.image_link).
|
|
216
|
+
- [Item.quantity](https://amazon-orders.readthedocs.io/api.html#amazonorders.entity.item.Item.quantity).
|
|
197
217
|
- `version` command to CLI.
|
|
198
218
|
- Test improvements.
|
|
199
219
|
|
|
200
220
|
### Changed
|
|
201
221
|
|
|
202
222
|
- Migrated to using CSS selectors
|
|
203
|
-
in [`AmazonSession`](https://amazon-orders.readthedocs.io/
|
|
223
|
+
in [`AmazonSession`](https://amazon-orders.readthedocs.io/api.html#amazonorders.session.AmazonSession)
|
|
204
224
|
- Migrated to using CSS selectors
|
|
205
|
-
in [`AmazonOrders`](https://amazon-orders.readthedocs.io/
|
|
225
|
+
in [`AmazonOrders`](https://amazon-orders.readthedocs.io/api.html#amazonorders.orders.AmazonOrders)
|
|
206
226
|
|
|
207
227
|
## [1.0.4](https://github.com/alexdlaird/amazon-orders/compare/1.0.3...1.0.4) - 2024-01-24
|
|
208
228
|
|
|
@@ -211,13 +231,13 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
211
231
|
- A new OTP auth flow from Amazon that can occur after Captcha.
|
|
212
232
|
- Parameters `--max-auth-attempts` and `--output-dir` to CLI.
|
|
213
233
|
- `DEFAULT_OUTPUT_DIR`, which defaults to `os.getcwd()`, but allows users to change where output files are written.
|
|
214
|
-
- [`Troubleshooting`](https://amazon-orders.readthedocs.io/
|
|
234
|
+
- [`Troubleshooting`](https://amazon-orders.readthedocs.io/troubleshooting.html) section to the docs.
|
|
215
235
|
- Test improvements, including the ability to run dynamic tests using private order data from JSON files.
|
|
216
236
|
|
|
217
237
|
### Changed
|
|
218
238
|
|
|
219
239
|
- Improved string representations of entities,
|
|
220
|
-
including [`Order`](https://amazon-orders.readthedocs.io/
|
|
240
|
+
including [`Order`](https://amazon-orders.readthedocs.io/api.html#amazonorders.entity.order.Order), moved
|
|
221
241
|
string representation of all fields back to `cli.py` out of the `__str__` method.
|
|
222
242
|
- Moved `DEFAULT_COOKIE_JAR_PATH` to `conf.py`.
|
|
223
243
|
|
|
@@ -246,7 +266,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
246
266
|
|
|
247
267
|
- Auth flow now also checks session cookies in addition to parsing the page for signs of login.
|
|
248
268
|
- All fields to string representation
|
|
249
|
-
of [`Order`](https://amazon-orders.readthedocs.io/
|
|
269
|
+
of [`Order`](https://amazon-orders.readthedocs.io/api.html#amazonorders.entity.order.Order), so they are not
|
|
250
270
|
output on the CLI.
|
|
251
271
|
- `logout` command to CLI.
|
|
252
272
|
- Documentation improvements.
|
|
@@ -255,7 +275,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
255
275
|
### Fixed
|
|
256
276
|
|
|
257
277
|
- Improvements to CLI, including error message cleanup on auth exceptions.
|
|
258
|
-
- [`Order.order_details_link`](https://amazon-orders.readthedocs.io/
|
|
278
|
+
- [`Order.order_details_link`](https://amazon-orders.readthedocs.io/api.html#amazonorders.entity.order.Order.order_details_link)
|
|
259
279
|
is now properly populated even on the details page.
|
|
260
280
|
- `.gitattributes` to HTML files are now ignore by Linguist.
|
|
261
281
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: amazon-orders
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: A CLI and library for interacting with Amazon order history.
|
|
5
5
|
Maintainer-email: Alex Laird <contact@alexlaird.com>
|
|
6
6
|
License: MIT License
|
|
@@ -71,7 +71,7 @@ Requires-Dist: types-beautifulsoup4; extra == "docs"
|
|
|
71
71
|
Requires-Dist: types-Pillow; extra == "docs"
|
|
72
72
|
Requires-Dist: types-PyYAML; extra == "docs"
|
|
73
73
|
|
|
74
|
-
<p align="center"><img alt="amazon-orders - a python library" src="https://amazon-orders.readthedocs.io/
|
|
74
|
+
<p align="center"><img alt="amazon-orders - a python library" src="https://amazon-orders.readthedocs.io/_images/logo.png" /></p>
|
|
75
75
|
|
|
76
76
|
[](https://pypi.org/project/amazon-orders)
|
|
77
77
|
[](https://pypi.org/project/amazon-orders)
|
|
@@ -83,9 +83,9 @@ Requires-Dist: types-PyYAML; extra == "docs"
|
|
|
83
83
|
`amazon-orders` is an unofficial library that provides a command line interface alongside a programmatic API that can
|
|
84
84
|
be used to interact with Amazon.com's consumer-facing website.
|
|
85
85
|
|
|
86
|
-
This works by parsing website data from Amazon.com. A
|
|
86
|
+
This works by parsing website data from Amazon.com. A periodic build validates functionality to ensure its
|
|
87
87
|
stability, but as Amazon provides no official API to use, this package may break at any time. This
|
|
88
|
-
package only supports the English version of the website.
|
|
88
|
+
package only officially supports the English version of the website.
|
|
89
89
|
|
|
90
90
|
## Installation
|
|
91
91
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<p align="center"><img alt="amazon-orders - a python library" src="https://amazon-orders.readthedocs.io/
|
|
1
|
+
<p align="center"><img alt="amazon-orders - a python library" src="https://amazon-orders.readthedocs.io/_images/logo.png" /></p>
|
|
2
2
|
|
|
3
3
|
[](https://pypi.org/project/amazon-orders)
|
|
4
4
|
[](https://pypi.org/project/amazon-orders)
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
`amazon-orders` is an unofficial library that provides a command line interface alongside a programmatic API that can
|
|
11
11
|
be used to interact with Amazon.com's consumer-facing website.
|
|
12
12
|
|
|
13
|
-
This works by parsing website data from Amazon.com. A
|
|
13
|
+
This works by parsing website data from Amazon.com. A periodic build validates functionality to ensure its
|
|
14
14
|
stability, but as Amazon provides no official API to use, this package may break at any time. This
|
|
15
|
-
package only supports the English version of the website.
|
|
15
|
+
package only officially supports the English version of the website.
|
|
16
16
|
|
|
17
17
|
## Installation
|
|
18
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: amazon-orders
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
4
4
|
Summary: A CLI and library for interacting with Amazon order history.
|
|
5
5
|
Maintainer-email: Alex Laird <contact@alexlaird.com>
|
|
6
6
|
License: MIT License
|
|
@@ -71,7 +71,7 @@ Requires-Dist: types-beautifulsoup4; extra == "docs"
|
|
|
71
71
|
Requires-Dist: types-Pillow; extra == "docs"
|
|
72
72
|
Requires-Dist: types-PyYAML; extra == "docs"
|
|
73
73
|
|
|
74
|
-
<p align="center"><img alt="amazon-orders - a python library" src="https://amazon-orders.readthedocs.io/
|
|
74
|
+
<p align="center"><img alt="amazon-orders - a python library" src="https://amazon-orders.readthedocs.io/_images/logo.png" /></p>
|
|
75
75
|
|
|
76
76
|
[](https://pypi.org/project/amazon-orders)
|
|
77
77
|
[](https://pypi.org/project/amazon-orders)
|
|
@@ -83,9 +83,9 @@ Requires-Dist: types-PyYAML; extra == "docs"
|
|
|
83
83
|
`amazon-orders` is an unofficial library that provides a command line interface alongside a programmatic API that can
|
|
84
84
|
be used to interact with Amazon.com's consumer-facing website.
|
|
85
85
|
|
|
86
|
-
This works by parsing website data from Amazon.com. A
|
|
86
|
+
This works by parsing website data from Amazon.com. A periodic build validates functionality to ensure its
|
|
87
87
|
stability, but as Amazon provides no official API to use, this package may break at any time. This
|
|
88
|
-
package only supports the English version of the website.
|
|
88
|
+
package only officially supports the English version of the website.
|
|
89
89
|
|
|
90
90
|
## Installation
|
|
91
91
|
|
|
@@ -278,7 +278,11 @@ Order #{}
|
|
|
278
278
|
order_str += f"\n Order Details Link: {order.order_details_link}"
|
|
279
279
|
order_str += f"\n Grand Total: ${order.grand_total:,.2f}"
|
|
280
280
|
order_str += f"\n Order Placed Date: {order.order_placed_date}"
|
|
281
|
-
|
|
281
|
+
if order.recipient:
|
|
282
|
+
order_str += f"\n {order.recipient}"
|
|
283
|
+
else:
|
|
284
|
+
order_str += "\n Recipient: None"
|
|
285
|
+
|
|
282
286
|
if order.payment_method:
|
|
283
287
|
order_str += f"\n Payment Method: {order.payment_method}"
|
|
284
288
|
if order.payment_method_last_4:
|
|
@@ -35,6 +35,7 @@ class AmazonOrdersConfig:
|
|
|
35
35
|
"selectors_class": "amazonorders.selectors.Selectors",
|
|
36
36
|
"order_class": "amazonorders.entity.order.Order",
|
|
37
37
|
"shipment_class": "amazonorders.entity.shipment.Shipment",
|
|
38
|
+
"item_class": "amazonorders.entity.item.Item",
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
if os.path.exists(self.config_path):
|
|
@@ -62,11 +63,13 @@ class AmazonOrdersConfig:
|
|
|
62
63
|
selectors_class_split = self.selectors_class.split(".")
|
|
63
64
|
order_class_split = self.order_class.split(".")
|
|
64
65
|
shipment_class_split = self.shipment_class.split(".")
|
|
66
|
+
item_class_split = self.item_class.split(".")
|
|
65
67
|
|
|
66
68
|
self.constants = util.load_class(constants_class_split[:-1], constants_class_split[-1])()
|
|
67
69
|
self.selectors = util.load_class(selectors_class_split[:-1], selectors_class_split[-1])()
|
|
68
70
|
self.order_cls = util.load_class(order_class_split[:-1], order_class_split[-1])
|
|
69
71
|
self.shipment_cls = util.load_class(shipment_class_split[:-1], shipment_class_split[-1])
|
|
72
|
+
self.item_cls = util.load_class(item_class_split[:-1], item_class_split[-1])
|
|
70
73
|
|
|
71
74
|
def __getattr__(self,
|
|
72
75
|
key: str) -> Any:
|
|
@@ -4,8 +4,7 @@ __license__ = "MIT"
|
|
|
4
4
|
import json
|
|
5
5
|
import logging
|
|
6
6
|
from datetime import date, datetime
|
|
7
|
-
from typing import List, Optional, TypeVar, Union
|
|
8
|
-
from urllib.parse import parse_qs, urlparse
|
|
7
|
+
from typing import Any, List, Optional, TypeVar, Union
|
|
9
8
|
|
|
10
9
|
from bs4 import BeautifulSoup, Tag
|
|
11
10
|
|
|
@@ -15,7 +14,6 @@ from amazonorders.entity.item import Item
|
|
|
15
14
|
from amazonorders.entity.parsable import Parsable
|
|
16
15
|
from amazonorders.entity.recipient import Recipient
|
|
17
16
|
from amazonorders.entity.shipment import Shipment
|
|
18
|
-
from amazonorders.exception import AmazonOrdersError
|
|
19
17
|
|
|
20
18
|
logger = logging.getLogger(__name__)
|
|
21
19
|
|
|
@@ -42,7 +40,9 @@ class Order(Parsable):
|
|
|
42
40
|
#: The Order Items.
|
|
43
41
|
self.items: List[Item] = clone.items if clone and not full_details else self._parse_items()
|
|
44
42
|
#: The Order number.
|
|
45
|
-
self.order_number: str = clone.order_number if clone else self.
|
|
43
|
+
self.order_number: str = clone.order_number if clone else self.safe_simple_parse(
|
|
44
|
+
selector=self.config.selectors.FIELD_ORDER_NUMBER_SELECTOR,
|
|
45
|
+
required=True)
|
|
46
46
|
#: The Order details link.
|
|
47
47
|
self.order_details_link: Optional[str] = clone.order_details_link if clone else self.safe_parse(
|
|
48
48
|
self._parse_order_details_link)
|
|
@@ -84,6 +84,9 @@ class Order(Parsable):
|
|
|
84
84
|
return f"Order #{self.order_number}: {self.items}"
|
|
85
85
|
|
|
86
86
|
def _parse_shipments(self) -> List[Shipment]:
|
|
87
|
+
if not self.parsed:
|
|
88
|
+
return []
|
|
89
|
+
|
|
87
90
|
shipments: List[Shipment] = [self.config.shipment_cls(x, self.config)
|
|
88
91
|
for x in util.select(self.parsed,
|
|
89
92
|
self.config.selectors.SHIPMENT_ENTITY_SELECTOR)]
|
|
@@ -91,8 +94,12 @@ class Order(Parsable):
|
|
|
91
94
|
return shipments
|
|
92
95
|
|
|
93
96
|
def _parse_items(self) -> List[Item]:
|
|
94
|
-
|
|
95
|
-
|
|
97
|
+
if not self.parsed:
|
|
98
|
+
return []
|
|
99
|
+
|
|
100
|
+
items: List[Item] = [self.config.item_cls(x, self.config)
|
|
101
|
+
for x in util.select(self.parsed,
|
|
102
|
+
self.config.selectors.ITEM_ENTITY_SELECTOR)]
|
|
96
103
|
items.sort()
|
|
97
104
|
return items
|
|
98
105
|
|
|
@@ -104,21 +111,6 @@ class Order(Parsable):
|
|
|
104
111
|
|
|
105
112
|
return value
|
|
106
113
|
|
|
107
|
-
def _parse_order_number(self) -> str:
|
|
108
|
-
try:
|
|
109
|
-
order_details_link = self._parse_order_details_link()
|
|
110
|
-
except Exception:
|
|
111
|
-
# We're not using safe_parse here because it's fine if this fails, no need for noise
|
|
112
|
-
order_details_link = None
|
|
113
|
-
|
|
114
|
-
if order_details_link:
|
|
115
|
-
parsed_url = urlparse(order_details_link)
|
|
116
|
-
value = parse_qs(parsed_url.query)["orderID"][0]
|
|
117
|
-
else:
|
|
118
|
-
value = self.simple_parse(self.config.selectors.FIELD_ORDER_NUMBER_SELECTOR, required=True)
|
|
119
|
-
|
|
120
|
-
return value
|
|
121
|
-
|
|
122
114
|
def _parse_grand_total(self) -> float:
|
|
123
115
|
value = self.simple_parse(self.config.selectors.FIELD_ORDER_GRAND_TOTAL_SELECTOR)
|
|
124
116
|
|
|
@@ -150,7 +142,7 @@ class Order(Parsable):
|
|
|
150
142
|
|
|
151
143
|
return value
|
|
152
144
|
|
|
153
|
-
def _parse_recipient(self) -> Recipient:
|
|
145
|
+
def _parse_recipient(self) -> Optional[Recipient]:
|
|
154
146
|
value = util.select_one(self.parsed, self.config.selectors.FIELD_ORDER_ADDRESS_SELECTOR)
|
|
155
147
|
|
|
156
148
|
if not value:
|
|
@@ -172,13 +164,12 @@ class Order(Parsable):
|
|
|
172
164
|
parsed_parent,
|
|
173
165
|
self.config.selectors.FIELD_ORDER_ADDRESS_FALLBACK_2_SELECTOR
|
|
174
166
|
)
|
|
175
|
-
if not parent_tag:
|
|
176
|
-
raise AmazonOrdersError(
|
|
177
|
-
"FIELD_ORDER_ADDRESS_FALLBACK_2_SELECTOR resulted in None, but it's required. "
|
|
178
|
-
"Check if Amazon changed the expected HTML."
|
|
179
|
-
) # pragma: no cover
|
|
180
167
|
|
|
181
|
-
|
|
168
|
+
if parent_tag:
|
|
169
|
+
value = BeautifulSoup(str(parent_tag.contents[0]).strip(), "html.parser")
|
|
170
|
+
|
|
171
|
+
if not value:
|
|
172
|
+
return None
|
|
182
173
|
|
|
183
174
|
return Recipient(value, self.config)
|
|
184
175
|
|
|
@@ -50,6 +50,11 @@ class Shipment(Parsable):
|
|
|
50
50
|
return str(self.items) < str(other.items)
|
|
51
51
|
|
|
52
52
|
def _parse_items(self) -> List[Item]:
|
|
53
|
-
|
|
53
|
+
if not self.parsed:
|
|
54
|
+
return []
|
|
55
|
+
|
|
56
|
+
items: List[Item] = [self.config.item_cls(x, self.config)
|
|
57
|
+
for x in util.select(self.parsed,
|
|
58
|
+
self.config.selectors.ITEM_ENTITY_SELECTOR)]
|
|
54
59
|
items.sort()
|
|
55
60
|
return items
|
|
@@ -73,9 +73,15 @@ class AmazonOrders:
|
|
|
73
73
|
response_parsed = self.amazon_session.last_response_parsed
|
|
74
74
|
|
|
75
75
|
for order_tag in util.select(response_parsed, self.config.selectors.ORDER_HISTORY_ENTITY_SELECTOR):
|
|
76
|
-
order = self.config.order_cls(order_tag, self.config)
|
|
76
|
+
order: Order = self.config.order_cls(order_tag, self.config)
|
|
77
77
|
|
|
78
78
|
if full_details:
|
|
79
|
+
if not order.order_details_link:
|
|
80
|
+
logger.warning(f"order_details_link for Order {order.order_number} did not populate, "
|
|
81
|
+
f"cannot read full details.")
|
|
82
|
+
|
|
83
|
+
continue
|
|
84
|
+
|
|
79
85
|
self.amazon_session.get(order.order_details_link)
|
|
80
86
|
order_details_tag = util.select_one(self.amazon_session.last_response_parsed,
|
|
81
87
|
self.config.selectors.ORDER_DETAILS_ENTITY_SELECTOR)
|
|
@@ -36,7 +36,7 @@ class Selectors:
|
|
|
36
36
|
##########################################################################
|
|
37
37
|
|
|
38
38
|
ORDER_HISTORY_ENTITY_SELECTOR = ["div.order", "div.order-card"]
|
|
39
|
-
ORDER_DETAILS_ENTITY_SELECTOR = ["div#orderDetails", "[data-component='orderCard']"]
|
|
39
|
+
ORDER_DETAILS_ENTITY_SELECTOR = ["div#orderDetails", "div#ordersContainer", "[data-component='orderCard']"]
|
|
40
40
|
ITEM_ENTITY_SELECTOR = ["div:has(> div.yohtmlc-item)", ".item-box", "[data-component='purchasedItems']"]
|
|
41
41
|
SHIPMENT_ENTITY_SELECTOR = ["div.shipment", "div.delivery-box", "[data-component='shipments']"]
|
|
42
42
|
|
|
@@ -61,7 +61,7 @@ class Selectors:
|
|
|
61
61
|
"div.a-span3"]
|
|
62
62
|
FIELD_ORDER_PAYMENT_METHOD_SELECTOR = "img.pmts-payment-credit-card-instrument-logo"
|
|
63
63
|
FIELD_ORDER_PAYMENT_METHOD_LAST_4_SELECTOR = "img.pmts-payment-credit-card-instrument-logo"
|
|
64
|
-
FIELD_ORDER_SUBTOTALS_TAG_ITERATOR_SELECTOR = "div#od-subtotals div.a-row"
|
|
64
|
+
FIELD_ORDER_SUBTOTALS_TAG_ITERATOR_SELECTOR = ["div#od-subtotals div.a-row", "[data-component='orderSubtotals']"]
|
|
65
65
|
FIELD_ORDER_SUBTOTALS_INNER_TAG_SELECTOR = "div.a-span-last"
|
|
66
66
|
FIELD_ORDER_ADDRESS_SELECTOR = "div.displayAddressDiv"
|
|
67
67
|
FIELD_ORDER_ADDRESS_FALLBACK_1_SELECTOR = "div.recipient span.a-declarative"
|
|
@@ -50,6 +50,7 @@ class TestConf(TestCase):
|
|
|
50
50
|
with open(config.config_path, "r") as f:
|
|
51
51
|
self.assertEqual("""constants_class: amazonorders.constants.Constants
|
|
52
52
|
cookie_jar_path: {}
|
|
53
|
+
item_class: amazonorders.entity.item.Item
|
|
53
54
|
max_auth_attempts: 10
|
|
54
55
|
order_class: amazonorders.entity.order.Order
|
|
55
56
|
output_dir: {}
|
|
@@ -204,7 +204,8 @@ class TestOrders(UnitTestCase):
|
|
|
204
204
|
@responses.activate
|
|
205
205
|
def test_temp_order_history_file(self):
|
|
206
206
|
"""
|
|
207
|
-
This test
|
|
207
|
+
This test can be used to drop in an order history page at tests/output/temp-order-history.html to easily
|
|
208
|
+
run a test against it for debugging purposes.
|
|
208
209
|
"""
|
|
209
210
|
# GIVEN
|
|
210
211
|
self.amazon_session.is_authenticated = True
|
|
@@ -239,6 +240,10 @@ class TestOrders(UnitTestCase):
|
|
|
239
240
|
"place it at tests/output/temp-order-details.html")
|
|
240
241
|
@responses.activate
|
|
241
242
|
def test_temp_order_details_file(self):
|
|
243
|
+
"""
|
|
244
|
+
This test can be used to drop in an order details page at tests/output/temp-order-details.html to easily
|
|
245
|
+
run a test against it for debugging purposes.
|
|
246
|
+
"""
|
|
242
247
|
# GIVEN
|
|
243
248
|
self.amazon_session.is_authenticated = True
|
|
244
249
|
order_id = "temp-1234"
|
|
@@ -358,10 +358,11 @@ class TestCase(unittest.TestCase):
|
|
|
358
358
|
self.assertIsNotNone(order.grand_total)
|
|
359
359
|
self.assertIsNotNone(order.order_details_link)
|
|
360
360
|
self.assertIsNotNone(order.order_placed_date)
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
361
|
+
if order.recipient:
|
|
362
|
+
self.assertIsNotNone(order.recipient.name)
|
|
363
|
+
self.assertIsNotNone(order.recipient.address)
|
|
364
|
+
self.assertGreaterEqual(len(order.shipments), 1)
|
|
365
|
+
self.assertEqual(str(order.items), str(order.shipments[0].items))
|
|
365
366
|
self.assertGreaterEqual(len(order.items), 1)
|
|
366
367
|
self.assertIsNotNone(order.items[0].title)
|
|
367
368
|
self.assertIsNotNone(order.items[0].link)
|
|
@@ -372,10 +373,12 @@ class TestCase(unittest.TestCase):
|
|
|
372
373
|
self.assertIsNotNone(order.payment_method)
|
|
373
374
|
self.assertEqual(4, len(order.payment_method_last_4))
|
|
374
375
|
self.assertIsNotNone(order.subtotal)
|
|
375
|
-
|
|
376
|
+
if order.recipient:
|
|
377
|
+
self.assertIsNotNone(order.shipping_total)
|
|
376
378
|
self.assertIsNotNone(order.total_before_tax)
|
|
377
379
|
self.assertIsNotNone(order.estimated_tax)
|
|
378
380
|
# As of April 2024, this is no longer shown in Order History
|
|
379
381
|
# self.assertIsNotNone(order.items[0].condition)
|
|
380
|
-
|
|
381
|
-
|
|
382
|
+
if order.recipient:
|
|
383
|
+
self.assertIsNotNone(order.items[0].price)
|
|
384
|
+
self.assertIsNotNone(order.items[0].seller.name)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|