Passed
Push — master ( c0e452...1f19b9 )
by Jared
55s
created

Refund::createOrReverse()   C

Complexity

Conditions 7
Paths 22

Size

Total Lines 44
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 44
rs 6.7272
cc 7
eloc 28
nc 22
nop 3
1
<?php
2
namespace CultureKings\Afterpay\Service\InStore;
3
4
use CultureKings\Afterpay\Exception\ApiException;
5
use CultureKings\Afterpay\Model;
6
use GuzzleHttp\Exception\BadResponseException;
7
use GuzzleHttp\Exception\RequestException;
8
use GuzzleHttp\HandlerStack;
9
10
/**
11
 * Class Refund
12
 * @package CultureKings\Afterpay\Service\InStore
13
 */
14
class Refund extends AbstractService
15
{
16
    const ERROR_CONFLICT = 409;
17
    const ERROR_INVALID_ORDER_MERCHANT_REFERENCE = 412;
18
    const ERROR_PRECONDITION_FAILED = 412;
19
    const ERROR_INVALID_AMOUNT = 412;
20
    const ERROR_MSG_PRECONDITION_FAILED = 'precondition_failed';
21
22
    /**
23
     * @param Model\InStore\Refund $refund
24
     * @param HandlerStack|null    $stack
25
     *
26
     * @return Model\InStore\Refund|array|\JMS\Serializer\scalar|object
27
     */
28
    public function create(Model\InStore\Refund $refund, HandlerStack $stack = null)
29
    {
30
        try {
31
            $params = $this->generateParams(
32
                $refund,
33
                $stack
34
            );
35
36
            $result = $this->getClient()->post('refunds', $params);
37
38
            return $this->getSerializer()->deserialize(
39
                (string) $result->getBody(),
40
                Model\InStore\Refund::class,
41
                'json'
42
            );
43
        } catch (BadResponseException $exception) {
44
            throw new ApiException(
45
                $this->getSerializer()->deserialize(
46
                    (string) $exception->getResponse()->getBody(),
47
                    Model\ErrorResponse::class,
48
                    'json'
49
                ),
50
                $exception
51
            );
52
        }
53
    }
54
55
    /**
56
     * @param Model\InStore\Reversal $reversal
57
     * @param HandlerStack|null      $stack
58
     *
59
     * @return array|\JMS\Serializer\scalar|Model\InStore\Reversal
60
     */
61
    public function reverse(Model\InStore\Reversal $reversal, HandlerStack $stack = null)
62
    {
63
        try {
64
            $params = $this->generateParams(
65
                $reversal,
66
                $stack
67
            );
68
69
            $result = $this->getClient()->post('refunds/reverse', $params);
70
71
            return $this->getSerializer()->deserialize(
72
                (string) $result->getBody(),
73
                Model\InStore\Reversal::class,
74
                'json'
75
            );
76
        } catch (RequestException $e) {
77
            throw new ApiException(
78
                $this->getSerializer()->deserialize(
79
                    (string) $e->getResponse()->getBody(),
80
                    Model\ErrorResponse::class,
81
                    'json'
82
                ),
83
                $e
84
            );
85
        }
86
    }
87
88
    /**
89
     * Helper method to automatically attempt to reverse a refund if an error occurs.
90
     *
91
     * Refund reversal model does not have to be passed in and will be automatically generated if not.
92
     *
93
     * @param Model\InStore\Refund        $refund
94
     * @param Model\InStore\Reversal|null $refundReversal
95
     * @param HandlerStack|null           $stack
96
     *
97
     * @return Model\InStore\Refund|Model\InStore\Reversal|array|\JMS\Serializer\scalar|object
98
     */
99
    public function createOrReverse(
100
        Model\InStore\Refund $refund,
101
        Model\InStore\Reversal $refundReversal = null,
102
        HandlerStack $stack = null
103
    ) {
104
        try {
105
            return $this->create($refund, $stack);
106
        } catch (ApiException $refundException) {
107
            // http://docs.afterpay.com.au/instore-api-v1.html#create-refund
108
            // Should a success or error response (with exception to 409 conflict) not be received,
109
            // the POS should queue the request ID for reversal
110
            if ($refundException->getErrorResponse()->getErrorCode() == self::ERROR_CONFLICT) {
111
                throw $refundException;
112
            }
113
            $errorResponse = $refundException->getErrorResponse();
114
        } catch (RequestException $refundException) {
115
            // a timeout or other exception has occurred. attempt a reversal
116
            $errorResponse = new Model\ErrorResponse();
117
            $errorResponse->setHttpStatusCode($refundException->getResponse()->getStatusCode());
118
            $errorResponse->setMessage($refundException->getMessage());
119
        }
120
121
        $now = new \DateTime();
122
        if ($refundReversal === null) {
123
            $refundReversal = new Model\InStore\Reversal();
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $refundReversal. This often makes code more readable.
Loading history...
124
            $refundReversal->setReversingRequestId($refund->getRequestId());
125
            $refundReversal->setRequestedAt($now);
126
        }
127
128
        try {
129
            $reversal = $this->reverse($refundReversal, $stack);
130
            $reversal->setErrorReason($errorResponse);
131
132
            return $reversal;
133
        } catch (ApiException $reversalException) {
134
            $reversalErrorResponse = $reversalException->getErrorResponse();
135
            if ($reversalErrorResponse->getErrorCode() === self::ERROR_MSG_PRECONDITION_FAILED) {
136
                // there was trouble reversing probably because the refund failed
137
                throw $refundException;
138
            }
139
140
            throw $reversalException;
141
        }
142
    }
143
}
144