amazon-orders 3.2.6__tar.gz → 3.2.7__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-3.2.6 → amazon_orders-3.2.7}/CHANGELOG.md +7 -1
- {amazon_orders-3.2.6/amazon_orders.egg-info → amazon_orders-3.2.7}/PKG-INFO +1 -1
- {amazon_orders-3.2.6 → amazon_orders-3.2.7/amazon_orders.egg-info}/PKG-INFO +1 -1
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/__init__.py +1 -1
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/entity/order.py +2 -2
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/orders.py +0 -5
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/selectors.py +5 -5
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/tests/test_cli.py +1 -1
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/tests/test_orders.py +17 -5
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/tests/test_transactions.py +26 -32
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/LICENSE +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/MANIFEST.in +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/README.md +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazon_orders.egg-info/SOURCES.txt +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazon_orders.egg-info/dependency_links.txt +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazon_orders.egg-info/entry_points.txt +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazon_orders.egg-info/requires.txt +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazon_orders.egg-info/top_level.txt +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/banner.txt +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/cli.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/conf.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/constants.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/entity/__init__.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/entity/item.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/entity/parsable.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/entity/recipient.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/entity/seller.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/entity/shipment.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/entity/transaction.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/exception.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/forms.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/session.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/transactions.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/amazonorders/util.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/pyproject.toml +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/setup.cfg +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/tests/test_conf.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/tests/test_session.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/tests/test_util.py +0 -0
- {amazon_orders-3.2.6 → amazon_orders-3.2.7}/tests/testcase.py +0 -0
|
@@ -4,7 +4,13 @@ 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/3.2.
|
|
7
|
+
## [Unreleased](https://github.com/alexdlaird/amazon-orders/compare/3.2.7...HEAD)
|
|
8
|
+
|
|
9
|
+
## [3.2.7](https://github.com/alexdlaird/amazon-orders/compare/3.2.6...3.2.7) - 2025-02-17
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Fixes for parsing Amazon Fresh and Whole Foods Market orders, so they no longer need to be skipped (but their Items and Shipments will still be empty).
|
|
8
14
|
|
|
9
15
|
## [3.2.6](https://github.com/alexdlaird/amazon-orders/compare/3.2.5...3.2.6) - 2025-02-17
|
|
10
16
|
|
|
@@ -92,7 +92,7 @@ class Order(Parsable):
|
|
|
92
92
|
return f"Order #{self.order_number}: {self.items}"
|
|
93
93
|
|
|
94
94
|
def _parse_shipments(self) -> List[Shipment]:
|
|
95
|
-
if not self.parsed:
|
|
95
|
+
if not self.parsed or len(util.select(self.parsed, self.config.selectors.ORDER_SKIP_ITEMS)) > 0:
|
|
96
96
|
return []
|
|
97
97
|
|
|
98
98
|
shipments: List[Shipment] = [self.config.shipment_cls(x, self.config)
|
|
@@ -102,7 +102,7 @@ class Order(Parsable):
|
|
|
102
102
|
return shipments
|
|
103
103
|
|
|
104
104
|
def _parse_items(self) -> List[Item]:
|
|
105
|
-
if not self.parsed:
|
|
105
|
+
if not self.parsed or len(util.select(self.parsed, self.config.selectors.ORDER_SKIP_ITEMS)) > 0:
|
|
106
106
|
return []
|
|
107
107
|
|
|
108
108
|
items: List[Item] = [self.config.item_cls(x, self.config)
|
|
@@ -73,11 +73,6 @@ 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
|
-
# First check if this Order is known to be of a type that we do not currently have a way to support
|
|
77
|
-
# parsing, meaning it should be skipped
|
|
78
|
-
if util.select(order_tag, self.config.selectors.ORDER_HISTORY_BRAND_SELECTOR):
|
|
79
|
-
continue
|
|
80
|
-
|
|
81
76
|
order: Order = self.config.order_cls(order_tag, self.config)
|
|
82
77
|
|
|
83
78
|
if full_details:
|
|
@@ -55,12 +55,12 @@ class Selectors:
|
|
|
55
55
|
SHIPMENT_ENTITY_SELECTOR = ["[data-component='orderCard'] [data-component='shipments'] .a-box",
|
|
56
56
|
"div.shipment",
|
|
57
57
|
"div.delivery-box"]
|
|
58
|
-
# Selectors defined here
|
|
59
|
-
#
|
|
60
|
-
|
|
61
|
-
# Amazon Fresh
|
|
58
|
+
# Selectors defined here mean we don't have a reliable way to parse all details in an Order, so Items and
|
|
59
|
+
# Shipments will be skipped
|
|
60
|
+
ORDER_SKIP_ITEMS = [
|
|
61
|
+
# Identifies an Amazon Fresh order
|
|
62
62
|
".brand-info-box .brand-logo img",
|
|
63
|
-
# Whole Foods Market
|
|
63
|
+
# Identifies a Whole Foods Market order
|
|
64
64
|
"a.yohtmlc-order-details-link[href^='/wholefoodsmarket']"
|
|
65
65
|
]
|
|
66
66
|
|
|
@@ -92,7 +92,7 @@ class TestCli(UnitTestCase):
|
|
|
92
92
|
mock_get_today.date.today.return_value = datetime.date(2024, 10, 11)
|
|
93
93
|
days = 1
|
|
94
94
|
self.given_login_responses_success()
|
|
95
|
-
with open(os.path.join(self.RESOURCES_DIR, "transactions", "get-transactions.html"),
|
|
95
|
+
with open(os.path.join(self.RESOURCES_DIR, "transactions", "get-transactions-snippet.html"),
|
|
96
96
|
"r", encoding="utf-8") as f:
|
|
97
97
|
resp = responses.add(
|
|
98
98
|
responses.GET,
|
|
@@ -98,7 +98,7 @@ class TestOrders(UnitTestCase):
|
|
|
98
98
|
orders = self.amazon_orders.get_order_history(year=year, start_index=start_index)
|
|
99
99
|
|
|
100
100
|
# THEN
|
|
101
|
-
self.assertEqual(
|
|
101
|
+
self.assertEqual(10, len(orders))
|
|
102
102
|
self.assertEqual(1, resp1.call_count)
|
|
103
103
|
self.assertEqual(1, resp2.call_count)
|
|
104
104
|
order = orders[5]
|
|
@@ -139,7 +139,7 @@ class TestOrders(UnitTestCase):
|
|
|
139
139
|
self.assertEqual(1, resp3.call_count)
|
|
140
140
|
|
|
141
141
|
@responses.activate
|
|
142
|
-
def
|
|
142
|
+
def test_get_order_history_fresh(self):
|
|
143
143
|
# GIVEN
|
|
144
144
|
self.amazon_session.is_authenticated = True
|
|
145
145
|
year = 2024
|
|
@@ -158,12 +158,18 @@ class TestOrders(UnitTestCase):
|
|
|
158
158
|
orders = self.amazon_orders.get_order_history(year=year, start_index=start_index)
|
|
159
159
|
|
|
160
160
|
# THEN
|
|
161
|
-
self.assertEqual(
|
|
161
|
+
self.assertEqual(10, len(orders))
|
|
162
162
|
self.assertEqual(1, resp1.call_count)
|
|
163
163
|
self.assertEqual(1, resp2.call_count)
|
|
164
|
+
order = orders[4]
|
|
165
|
+
self.assertEqual("111-2072777-8279433", order.order_number)
|
|
166
|
+
self.assertEqual(80.27, order.grand_total)
|
|
167
|
+
self.assertIsNotNone(order.order_details_link)
|
|
168
|
+
self.assertEqual(date(2025, 1, 3), order.order_placed_date)
|
|
169
|
+
self.assertEqual(0, len(order.items))
|
|
164
170
|
|
|
165
171
|
@responses.activate
|
|
166
|
-
def
|
|
172
|
+
def test_get_order_history_wholefoods(self):
|
|
167
173
|
# GIVEN
|
|
168
174
|
self.amazon_session.is_authenticated = True
|
|
169
175
|
year = 2024
|
|
@@ -182,9 +188,15 @@ class TestOrders(UnitTestCase):
|
|
|
182
188
|
orders = self.amazon_orders.get_order_history(year=year, start_index=start_index)
|
|
183
189
|
|
|
184
190
|
# THEN
|
|
185
|
-
self.assertEqual(
|
|
191
|
+
self.assertEqual(10, len(orders))
|
|
186
192
|
self.assertEqual(1, resp1.call_count)
|
|
187
193
|
self.assertEqual(1, resp2.call_count)
|
|
194
|
+
order = orders[7]
|
|
195
|
+
self.assertEqual("113-6307059-7336242", order.order_number)
|
|
196
|
+
self.assertEqual(62.92, order.grand_total)
|
|
197
|
+
self.assertIsNotNone(order.order_details_link)
|
|
198
|
+
self.assertEqual(date(2024, 12, 12), order.order_placed_date)
|
|
199
|
+
self.assertEqual(0, len(order.items))
|
|
188
200
|
|
|
189
201
|
@responses.activate
|
|
190
202
|
def test_get_order_history_full_details(self):
|
|
@@ -37,11 +37,9 @@ class TestOrders(UnitTestCase):
|
|
|
37
37
|
mock_get_today.date.today.return_value = datetime.date(2024, 10, 11)
|
|
38
38
|
days = 1
|
|
39
39
|
self.amazon_session.is_authenticated = True
|
|
40
|
-
with open(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
encoding="utf-8",
|
|
44
|
-
) as f:
|
|
40
|
+
with open(os.path.join(self.RESOURCES_DIR, "transactions", "get-transactions-snippet.html"),
|
|
41
|
+
"r",
|
|
42
|
+
encoding="utf-8") as f:
|
|
45
43
|
responses.add(
|
|
46
44
|
responses.GET,
|
|
47
45
|
f"{self.test_config.constants.TRANSACTION_HISTORY_LANDING_URL}",
|
|
@@ -71,11 +69,9 @@ class TestOrders(UnitTestCase):
|
|
|
71
69
|
mock_get_today.date.today.return_value = datetime.date(2025, 2, 13)
|
|
72
70
|
days = 30
|
|
73
71
|
self.amazon_session.is_authenticated = True
|
|
74
|
-
with open(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
encoding="utf-8",
|
|
78
|
-
) as f:
|
|
72
|
+
with open(os.path.join(self.RESOURCES_DIR, "transactions", "transactions-in-progress.html"),
|
|
73
|
+
"r",
|
|
74
|
+
encoding="utf-8") as f:
|
|
79
75
|
responses.add(
|
|
80
76
|
responses.GET,
|
|
81
77
|
f"{self.test_config.constants.TRANSACTION_HISTORY_LANDING_URL}",
|
|
@@ -109,29 +105,27 @@ class TestOrders(UnitTestCase):
|
|
|
109
105
|
|
|
110
106
|
def test_parse_transaction_form_tag(self):
|
|
111
107
|
# GIVEN
|
|
112
|
-
with open(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
encoding="utf-8",
|
|
116
|
-
) as f:
|
|
108
|
+
with open(os.path.join(self.RESOURCES_DIR, "transactions", "transaction-form-tag.html"),
|
|
109
|
+
"r",
|
|
110
|
+
encoding="utf-8") as f:
|
|
117
111
|
parsed = BeautifulSoup(f.read(), self.test_config.bs4_parser)
|
|
118
112
|
form_tag = parsed.select_one("form")
|
|
119
113
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
114
|
+
# WHEN
|
|
115
|
+
transactions, next_page_url, next_page_data = _parse_transaction_form_tag(
|
|
116
|
+
form_tag, self.test_config
|
|
117
|
+
)
|
|
124
118
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
119
|
+
# THEN
|
|
120
|
+
self.assertEqual(len(transactions), 2)
|
|
121
|
+
self.assertEqual(
|
|
122
|
+
next_page_url, "https://www.amazon.com:443/cpe/yourpayments/transactions"
|
|
123
|
+
)
|
|
124
|
+
self.assertEqual(
|
|
125
|
+
next_page_data,
|
|
126
|
+
{
|
|
127
|
+
"ppw-widgetState": "the-ppw-widgetState",
|
|
128
|
+
"ie": "UTF-8",
|
|
129
|
+
'ppw-widgetEvent:DefaultNextPageNavigationEvent:{"nextPageKey":"key"}': "",
|
|
130
|
+
},
|
|
131
|
+
)
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|