Coverage for amazonorders/orders.py: 98.04%

51 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-25 22:50 +0000

1import datetime 

2import logging 

3from typing import List, Optional 

4 

5from amazonorders.conf import DEFAULT_OUTPUT_DIR 

6from amazonorders.entity.order import Order 

7from amazonorders.exception import AmazonOrdersError 

8from amazonorders.session import BASE_URL, AmazonSession 

9 

10__author__ = "Alex Laird" 

11__copyright__ = "Copyright 2024, Alex Laird" 

12__version__ = "1.0.6" 

13 

14logger = logging.getLogger(__name__) 

15 

16ORDER_HISTORY_CARD_SELECTOR = "div[class*='order-card']:has(script)" 

17ORDER_DETAILS_DIV_SELECTOR = "div[id='orderDetails']" 

18NEXT_PAGE_LINK_SELECTOR = "ul[class*='a-pagination'] li[class*='a-last'] a" 

19 

20 

21class AmazonOrders: 

22 """ 

23 Using an authenticated :class:`~amazonorders.session.AmazonSession`, can be used to query Amazon 

24 for Order details and history. 

25 """ 

26 

27 def __init__(self, 

28 amazon_session: AmazonSession, 

29 debug: bool = False, 

30 output_dir: str = None) -> None: 

31 if not output_dir: 

32 output_dir = DEFAULT_OUTPUT_DIR 

33 

34 #: The AmazonSession to use for requests. 

35 self.amazon_session: AmazonSession = amazon_session 

36 

37 #: Set logger ``DEBUG`` and send output to ``stderr``. 

38 self.debug: bool = debug 

39 if self.debug: 

40 logger.setLevel(logging.DEBUG) 

41 #: The directory where any output files will be produced, defaults to ``conf.DEFAULT_OUTPUT_DIR``. 

42 self.output_dir = output_dir 

43 

44 def get_order_history(self, 

45 year: int = datetime.date.today().year, 

46 start_index: Optional[int] = None, 

47 full_details: bool = False) -> List[Order]: 

48 """ 

49 Get the Amazon order history for the given year. 

50 

51 :param year: The year for which to get history. 

52 :param start_index: The index to start at within the history. 

53 :param full_details: Will execute an additional request per Order in the retrieved history to fully populate it. 

54 :return: A list of the requested Orders. 

55 """ 

56 if not self.amazon_session.is_authenticated: 

57 raise AmazonOrdersError("Call AmazonSession.login() to authenticate first.") 

58 

59 orders = [] 

60 next_page = "{}/your-orders/orders?timeFilter=year-{}{}".format(BASE_URL, 

61 year, 

62 "&startIndex={}".format( 

63 start_index) if start_index else "") 

64 while next_page: 

65 self.amazon_session.get(next_page) 

66 response_parsed = self.amazon_session.last_response_parsed 

67 

68 for order_tag in response_parsed.select(ORDER_HISTORY_CARD_SELECTOR): 

69 order = Order(order_tag) 

70 

71 if full_details: 

72 self.amazon_session.get(order.order_details_link) 

73 order_details_tag = self.amazon_session.last_response_parsed.select_one(ORDER_DETAILS_DIV_SELECTOR) 

74 order = Order(order_details_tag, full_details=True, clone=order) 

75 

76 orders.append(order) 

77 

78 next_page = None 

79 if start_index is None: 

80 next_page_tag = response_parsed.select_one(NEXT_PAGE_LINK_SELECTOR) 

81 if next_page_tag: 

82 next_page = "{}{}".format(BASE_URL, next_page_tag["href"]) 

83 else: 

84 logger.debug("No next page") 

85 else: 

86 logger.debug("start_index is given, not paging") 

87 

88 return orders 

89 

90 def get_order(self, 

91 order_id: str) -> Order: 

92 """ 

93 Get the Amazon order represented by the ID. 

94 

95 :param order_id: The Amazon Order ID to lookup. 

96 :return: The requested Order. 

97 """ 

98 if not self.amazon_session.is_authenticated: 

99 raise AmazonOrdersError("Call AmazonSession.login() to authenticate first.") 

100 

101 self.amazon_session.get("{}/gp/your-account/order-details?orderID={}".format(BASE_URL, order_id)) 

102 

103 order_details_tag = self.amazon_session.last_response_parsed.select_one(ORDER_DETAILS_DIV_SELECTOR) 

104 order = Order(order_details_tag, full_details=True) 

105 

106 return order