diff --git a/payu/__init__.py b/payu/__init__.py
index da1eab0..88caf4f 100644
--- a/payu/__init__.py
+++ b/payu/__init__.py
@@ -15,4 +15,4 @@
#
__author__ = 'Presslabs'
-__version__ = '1.0.0-rc2'
+__version__ = '1.0.0'
diff --git a/payu/conf.py b/payu/conf.py
index 583f58d..d734953 100644
--- a/payu/conf.py
+++ b/payu/conf.py
@@ -29,7 +29,8 @@
'https://secure.payu.ro/order/alu/v3')
PAYU_IDN_URL = getattr(settings, 'PAYU_IDN_URL',
'https://secure.payu.ro/order/idn.php')
-
+PAYU_IOS_URL = getattr(settings, 'PAYU_IOS_URL',
+ 'https://secure.payu.ro/order/ios.php')
PAYU_TOKENS_URL = getattr(settings, 'PAYU_TOKENS_URL',
'https://secure.payu.ro/order/tokens/')
diff --git a/payu/models.py b/payu/models.py
index 65cba18..4b6d540 100644
--- a/payu/models.py
+++ b/payu/models.py
@@ -13,11 +13,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-import time
import hmac
-import hashlib
-from datetime import datetime
from collections import OrderedDict
+from datetime import datetime
import pytz
import requests
diff --git a/payu/utils.py b/payu/utils.py
new file mode 100644
index 0000000..f464f95
--- /dev/null
+++ b/payu/utils.py
@@ -0,0 +1,45 @@
+import hmac
+from collections import OrderedDict
+from xml.etree import ElementTree
+
+import requests
+
+from payu.conf import PAYU_IOS_URL, PAYU_MERCHANT, PAYU_MERCHANT_KEY
+
+
+def _signature(payload, merchant_key):
+ confirmation_hash = "".join(["%s%s" % (len(str(payload[field])),
+ payload[field])
+ for field in payload])
+ return hmac.new(merchant_key, confirmation_hash).hexdigest()
+
+
+def _build_payload(merchant, merchant_key, ref_no_ext):
+ payload = OrderedDict([
+ ('MERCHANT', merchant),
+ ('REFNOEXT', ref_no_ext)
+ ])
+ payload["HASH"] = _signature(payload, merchant_key)
+
+ return payload
+
+
+def get_instant_order_status(ipn):
+ """
+ :param ipn: A PayUIPN object containing the REFNOEXT attribute.
+ :return: A dict containing details about the status of the order.
+ """
+ payload = _build_payload(PAYU_MERCHANT, PAYU_MERCHANT_KEY, ipn.REFNOEXT)
+
+ response = requests.post(PAYU_IOS_URL, data=payload)
+
+ try:
+ parsed_response = ElementTree.fromstring(response.content)
+ except ElementTree.ParseError:
+ return {'error': "Couldn't parse the XML result from PayU.",
+ 'result': response.content}
+
+ if parsed_response.tag == 'Error':
+ return {'error': parsed_response.text.strip()}
+
+ return {child.tag: (child.text or '').strip() for child in parsed_response}
diff --git a/tests/test_ios.py b/tests/test_ios.py
new file mode 100644
index 0000000..e264797
--- /dev/null
+++ b/tests/test_ios.py
@@ -0,0 +1,80 @@
+from collections import OrderedDict
+
+import pytest
+from mock import MagicMock, patch
+from django_dynamic_fixture import G
+
+from payu.models import PayUIPN
+from payu.utils import _signature, _build_payload, get_instant_order_status
+
+
+def test_ios_signature():
+ # this data is taken from the PayU documentation
+
+ payload = OrderedDict([
+ ('MERCHANT', 'PAYUDEMO'),
+ ('REFNOEXT', 'EPAY10425')
+ ])
+
+ signature = _signature(payload, merchant_key='1231234567890123')
+
+ assert signature == '6cb19f366fd9709b078b593b1736a4ea'
+
+
+def test_ios_payload():
+ # this data is taken from the PayU documentation
+
+ payload = _build_payload(merchant='PAYUDEMO',
+ ref_no_ext='EPAY10425',
+ merchant_key='1231234567890123')
+
+ assert payload == OrderedDict([
+ ('MERCHANT', 'PAYUDEMO'),
+ ('REFNOEXT', 'EPAY10425'),
+ ('HASH', '6cb19f366fd9709b078b593b1736a4ea')
+ ])
+
+
+@pytest.mark.django_db
+@patch('payu.utils.requests')
+def test_ios_get_instant_order_status(mocked_requests):
+ response_content = """
+
+ 2017-07-12 12:16:20
+ 45459240
+ b3045b90-d11f-4c78-9f6b-79f54317df36
+ TEST
+ Visa/MasterCard/Eurocard
+ adc135ddd73f0f4fe3eb9d26b84c662d
+ """
+
+ mocked_requests.post.return_value = MagicMock(status_code=200, content=response_content)
+
+ ipn = G(PayUIPN)
+
+ status = get_instant_order_status(ipn)
+
+ assert status == {'HASH': 'adc135ddd73f0f4fe3eb9d26b84c662d',
+ 'PAYMETHOD': 'Visa/MasterCard/Eurocard',
+ 'REFNO': '45459240',
+ 'ORDER_STATUS': 'TEST',
+ 'ORDER_DATE': '2017-07-12 12:16:20',
+ 'REFNOEXT': 'b3045b90-d11f-4c78-9f6b-79f54317df36'}
+
+
+@pytest.mark.django_db
+@pytest.mark.parametrize('payu_response, expected_result', [
+ ('Limit calls for IOS exceeded!',
+ {'error': 'Limit calls for IOS exceeded!'}),
+ ('Access not permitted', {'error': "Couldn't parse the XML result from PayU.",
+ 'result': 'Access not permitted'}),
+])
+@patch('payu.utils.requests')
+def test_ios_get_instant_order_status_error(mocked_requests, payu_response, expected_result):
+ mocked_requests.post.return_value = MagicMock(status_code=200, content=payu_response)
+
+ ipn = G(PayUIPN)
+
+ result = get_instant_order_status(ipn)
+
+ assert result == expected_result