Repository: amadeus4dev/amadeus-python

Issue:
To add support Hotel Booking V2

Discussion:
sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=amadeus4dev_amadeus-python&pullRequest=212) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=amadeus4dev_amadeus-python&pullRequest=212&resolved=false&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=amadeus4dev_amadeus-python&pullRequest=212&resolutions=WONTFIX)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=amadeus4dev_amadeus-python&pullRequest=212&resolved=false&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=amadeus4dev_amadeus-python&pullRequest=212&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=amadeus4dev_amadeus-python&pullRequest=212)


sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=amadeus4dev_amadeus-python&pullRequest=212) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=amadeus4dev_amadeus-python&pullRequest=212&resolved=false&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=amadeus4dev_amadeus-python&pullRequest=212&resolutions=WONTFIX)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=amadeus4dev_amadeus-python&pullRequest=212&resolved=false&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/no-data-16px.png '') No data about Coverage  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=amadeus4dev_amadeus-python&pullRequest=212&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=amadeus4dev_amadeus-python&pullRequest=212)



Patch:
diff --git a/README.rst b/README.rst
index 4552ff3..0c1d78a 100644
--- a/README.rst
+++ b/README.rst
@@ -275,7 +275,15 @@ List of supported endpoints
     # Hotel Name Autocomplete
     amadeus.reference_data.locations.hotel.get(keyword='PARI', subType=[Hotel.HOTEL_GDS, Hotel.HOTEL_LEISURE])
 
-    # Hotel Booking
+    # Hotel Booking v2
+    # The offerId comes from the hotel_offer above
+    amadeus.booking.hotel_orders.post(
+        guests=guests, 
+        travel_agent=travel_agent,
+        room_associations=room_associations,
+        payment=payment)
+
+    # Hotel Booking v1
     # The offerId comes from the hotel_offer above
     amadeus.booking.hotel_bookings.post(offerId, guests, payments)
 
diff --git a/amadeus/booking/__init__.py b/amadeus/booking/__init__.py
index 1efb8e6..30f095b 100644
--- a/amadeus/booking/__init__.py
+++ b/amadeus/booking/__init__.py
@@ -1,5 +1,6 @@
 from ._flight_orders import FlightOrders
 from ._flight_order import FlightOrder
 from ._hotel_bookings import HotelBookings
+from ._hotel_orders import HotelOrders
 
-__all__ = ['FlightOrders', 'FlightOrder', 'HotelBookings']
+__all__ = ['FlightOrders', 'FlightOrder', 'HotelBookings', 'HotelOrders']
diff --git a/amadeus/booking/_hotel_orders.py b/amadeus/booking/_hotel_orders.py
new file mode 100644
index 0000000..8e4aa16
--- /dev/null
+++ b/amadeus/booking/_hotel_orders.py
@@ -0,0 +1,45 @@
+from amadeus.client.decorator import Decorator
+
+
+class HotelOrders(Decorator, object):
+    def post(self,
+             guests,
+             travel_agent,
+             room_associations=[],
+             payment={},
+             arrival_information={}):
+        '''
+        Book hotel(s) via Hotel Booking API V2
+
+        .. code-block:: python
+
+            amadeus.booking.hotel_orders.post(guests,
+                                              travel_agent,
+                                              room_associations,
+                                              payment,
+                                              arrival_information)
+
+        The parameters guests and room_associations can be passed as dictionary
+        or list of dictionaries. If they are dictionary in this method they are
+        converted to a list of dictionaries.
+
+        :rtype: amadeus.Response
+        :raises amadeus.ResponseError: if the request could not be completed
+        '''
+        guests_info = []
+        room_associations_info = []
+        if not isinstance(guests, list):
+            guests_info.append(guests)
+        else:
+            guests_info.extend(guests)
+        if not isinstance(room_associations, list):
+            room_associations_info.append(room_associations)
+        else:
+            room_associations_info.extend(room_associations)
+        body = {'data': {'type': 'hotel-order',
+                         'guests': guests_info,
+                         'travelAgent': travel_agent,
+                         'roomAssociations': room_associations_info,
+                         'arrivalInformation': arrival_information,
+                         'payment': payment}}
+        return self.client.post('/v2/booking/hotel-orders', body)
diff --git a/amadeus/namespaces/_booking.py b/amadeus/namespaces/_booking.py
index 94e64e3..332b3f5 100644
--- a/amadeus/namespaces/_booking.py
+++ b/amadeus/namespaces/_booking.py
@@ -1,6 +1,7 @@
 from amadeus.booking._flight_orders import FlightOrders
 from amadeus.booking._flight_order import FlightOrder
 from amadeus.booking._hotel_bookings import HotelBookings
+from amadeus.booking._hotel_orders import HotelOrders
 from amadeus.client.decorator import Decorator
 
 
@@ -9,9 +10,10 @@ class Booking(Decorator, object):
         Decorator.__init__(self, client)
         self.flight_orders = FlightOrders(client)
         self.hotel_bookings = HotelBookings(client)
+        self.hotel_orders = HotelOrders(client)
 
     def flight_order(self, flight_order_id):
         return FlightOrder(self.client, flight_order_id)
 
 
-__all__ = ['FlightOrders', 'FlightOrder', 'HotelBookings']
+__all__ = ['FlightOrders', 'FlightOrder', 'HotelBookings', 'HotelOrders']
diff --git a/docs/index.rst b/docs/index.rst
index 96fe572..364cfa5 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -218,6 +218,10 @@ Booking
 .. autoclass:: amadeus.booking.HotelBookings
   :members: post
 
+.. autoclass:: amadeus.booking.HotelOrders
+  :members: post
+
+
 Schedule/Flights
 ================
 


Test patch:
diff --git a/specs/namespaces/test_namespaces.py b/specs/namespaces/test_namespaces.py
index 4687e9a..856a702 100644
--- a/specs/namespaces/test_namespaces.py
+++ b/specs/namespaces/test_namespaces.py
@@ -55,6 +55,7 @@ def test_expected_paths(client):
     assert client.travel.from_base64 is not None
     assert client.booking.flight_orders is not None
     assert client.booking.flight_order is not None
+    assert client.booking.hotel_orders is not None
     assert client.schedule is not None
     assert client.schedule.flights is not None
     assert client.analytics is not None
@@ -435,6 +436,35 @@ def test_shopping_booking_hotel_bookings_post_list(client_setup):
     )
 
 
+def test_booking_hotel_orders_post(client_setup):
+    client_setup.booking.hotel_orders.post({'foo': 'bar'},
+                                           {'bar': 'foo'})
+    client_setup.post.assert_called_with(
+        '/v2/booking/hotel-orders',
+        {'data': {'type': 'hotel-order',
+                  'guests': [{'foo': 'bar'}],
+                  'travelAgent': {'bar': 'foo'},
+                  'roomAssociations': [],
+                  'payment': {},
+                  'arrivalInformation': {}}}
+    )
+
+
+def test_booking_hotel_orders_post_list(client_setup):
+    client_setup.booking.hotel_orders.post([{'foo': 'bar'}],
+                                           {'bar': 'foo'},
+                                           [{'a': 'b'}],)
+    client_setup.post.assert_called_with(
+        '/v2/booking/hotel-orders',
+        {'data': {'type': 'hotel-order',
+                  'guests': [{'foo': 'bar'}],
+                  'travelAgent': {'bar': 'foo'},
+                  'roomAssociations': [{'a': 'b'}],
+                  'payment': {},
+                  'arrivalInformation': {}}}
+    )
+
+
 def test_schedule_flights_get(client_setup):
     client_setup.schedule.flights.get(a='b')
     client_setup.get.assert_called_with(