6
6
7
7
use Magento \Framework \App \Config \ScopeConfigInterface ;
8
8
use Magento \Framework \DB \TransactionFactory ;
9
+ use Magento \Framework \Exception \AlreadyExistsException ;
9
10
use Magento \Framework \UrlInterface ;
10
11
use Magento \Sales \Api \Data \OrderInterface ;
11
12
use Magento \Sales \Model \Order ;
12
13
use Magento \Sales \Model \Order \Invoice ;
13
14
use Magento \Sales \Model \Order \Payment ;
15
+ use Magento \Sales \Model \Order \StatusFactory ;
14
16
use Magento \Sales \Model \OrderRepository ;
17
+ use Magento \Sales \Model \ResourceModel \Order \Status as StatusResource ;
18
+ use Magento \Sales \Model \ResourceModel \Order \StatusFactory as StatusResourceFactory ;
15
19
use Magento \Store \Model \ScopeInterface ;
16
20
use NoFrixion \Client \PaymentRequest ;
17
21
use Nofrixion \Payments \Model \OrderStatuses ;
@@ -25,22 +29,30 @@ class Data
25
29
private LoggerInterface $ logger ;
26
30
private OrderRepository $ orderRepository ;
27
31
private TransactionFactory $ transactionFactory ;
32
+ private StatusFactory $ statusFactory ;
33
+ private StatusResourceFactory $ statusResourceFactory ;
28
34
29
35
public const ORDER_ID_SEPARATOR = '- ' ;
30
-
36
+ private StatusResource \ CollectionFactory $ statusCollectionFactory ;
31
37
32
38
public function __construct (
33
39
ScopeConfigInterface $ scopeConfig ,
34
40
UrlInterface $ url ,
35
41
OrderRepository $ orderRepository ,
36
42
TransactionFactory $ transactionFactory ,
37
43
LoggerInterface $ logger ,
44
+ StatusFactory $ statusFactory ,
45
+ StatusResourceFactory $ statusResourceFactory ,
46
+ \Magento \Sales \Model \ResourceModel \Order \Status \CollectionFactory $ statusCollectionFactory
38
47
) {
39
48
$ this ->scopeConfig = $ scopeConfig ;
40
49
$ this ->url = $ url ;
41
50
$ this ->orderRepository = $ orderRepository ;
42
51
$ this ->transactionFactory = $ transactionFactory ;
43
52
$ this ->logger = $ logger ;
53
+ $ this ->statusFactory = $ statusFactory ;
54
+ $ this ->statusResourceFactory = $ statusResourceFactory ;
55
+ $ this ->statusCollectionFactory = $ statusCollectionFactory ;
44
56
}
45
57
46
58
public function getPaymentRequestClient (?int $ storeId = null ): PaymentRequest
@@ -76,10 +88,11 @@ public function createPaymentRequest(Order $order): array
76
88
$ amount = $ order ->getTotalDue ();
77
89
$ customerEmail = $ order ->getCustomerEmail ();
78
90
$ currency = $ order ->getOrderCurrencyCode ();
79
- $ paymentMethodTypes = array ('card ' , 'pisp ' );
91
+ $ paymentMethodTypes = $ this ->scopeConfig ->getValue ('payment/nofrixion/payment_options ' , 'stores ' , $ storeId );
92
+ $ paymentMethodTypes = explode (', ' , $ paymentMethodTypes );
80
93
$ originUrl = $ this ->url ->getBaseUrl (['_store ' => $ storeId ]);
81
94
$ nofrixionOrderId = $ this ->encodeOrderId ($ order );
82
- $ callbackUrl = $ this ->url ->getUrl ('nofrixion/redirect/returnAfterPayment ' , ['_secure ' => true , 'nofrixion_order_id ' => $ nofrixionOrderId ]);
95
+ $ callbackUrl = $ this ->url ->getUrl ('nofrixion/redirect/returnAfterPayment ' , ['_store ' => $ storeId , ' _secure ' => true , 'nofrixion_order_id ' => $ nofrixionOrderId ]);
83
96
$ amount = PreciseNumber::parseString ((string )$ amount );
84
97
if ($ order ->getCustomerId ()) {
85
98
$ customerId = (string )$ order ->getCustomerId ();
@@ -90,7 +103,10 @@ public function createPaymentRequest(Order $order): array
90
103
$ createCardToken = true ;
91
104
$ client = $ this ->getPaymentRequestClient ($ storeId );
92
105
$ originUrl = str_replace ('http:// ' , 'https:// ' , $ originUrl );
93
- $ paymentRequest = $ client ->createPaymentRequest ($ originUrl , $ callbackUrl , $ amount , $ customerEmail , $ currency , $ paymentMethodTypes , $ nofrixionOrderId , $ createCardToken , $ customerId );
106
+
107
+ $ webhookUrl = $ this ->url ->getUrl ('nofrixion/webhook/in ' , ['_secure ' => true ]);
108
+
109
+ $ paymentRequest = $ client ->createPaymentRequest ($ originUrl , $ callbackUrl , $ amount , $ customerEmail , $ currency , $ paymentMethodTypes , $ nofrixionOrderId , $ createCardToken , $ customerId , false , false , $ webhookUrl );
94
110
95
111
return $ paymentRequest ;
96
112
}
@@ -101,57 +117,77 @@ public function getPaymentRequest(string $id, int $storeId): array
101
117
return $ client ->getPaymentRequest ($ id );
102
118
}
103
119
104
- public function processPayment (string $ paymentRequestId , int $ storeId ): OrderInterface
120
+ public function processPayment (array $ paymentRequest ): OrderInterface
105
121
{
106
- $ paymentRequest = $ this ->getPaymentRequest ($ paymentRequestId , $ storeId );
107
122
$ nofrixionOrderId = $ paymentRequest ['orderID ' ];
108
123
$ magentoOrderId = $ this ->decodeOrderId ($ nofrixionOrderId );
109
124
110
125
$ order = $ this ->orderRepository ->get ($ magentoOrderId );
111
126
112
127
$ status = $ paymentRequest ['status ' ] ?? null ;
113
128
129
+ $ createInvoice = true ;
130
+ $ isPaid = false ;
114
131
$ newStatus = null ;
115
132
116
133
switch ($ status ) {
134
+ case 'Authorized ' :
135
+ $ newStatus = OrderStatuses::STATUS_CODE_AUTHORIZED_PAYMENT ;
136
+ $ createInvoice = false ;
137
+ $ isPaid = true ;
138
+ break ;
117
139
case 'OverPaid ' :
118
140
$ newStatus = OrderStatuses::STATUS_CODE_OVERPAID ;
119
-
141
+ $ isPaid = true ;
142
+ break ;
120
143
case 'FullyPaid ' :
121
- if ($ order ->getTotalDue () > 0 ) {
122
- if ($ newStatus === null ) {
123
- $ newStatus = OrderStatuses::STATUS_CODE_PAID_CORRECTLY ;
124
- }
125
-
126
- $ msg = 'Customer paid ' . $ paymentRequest ['amount ' ] . ' ' . $ paymentRequest ['currency ' ] . ' using the NoFrixion payment request with ID ' . $ paymentRequest ['id ' ];
127
- $ order ->addCommentToStatusHistory ($ msg , $ newStatus , true );
128
-
129
- $ invoice = $ order ->prepareInvoice ();
130
- $ invoice ->setRequestedCaptureCase (Invoice::CAPTURE_ONLINE );
131
-
132
- // We need to set this so the "Refund" button appears when creating a credit memo for an invoice.
133
- // Refunds only work when creating a credit memo for an invoice. Creating a credit memo for an order (and not a specific invoice) will not show the "Refund" button. Only the "Refund Offline" button will show.
134
- $ invoice ->setTransactionId ($ paymentRequest ['id ' ]);
135
-
136
- $ invoice ->register ();
137
-
138
- $ saveTransaction = $ this ->transactionFactory ->create ();
139
- $ saveTransaction ->addObject ($ invoice );
140
- $ saveTransaction ->addObject ($ order );
141
- $ saveTransaction ->save ();
142
- }
144
+ $ isPaid = true ;
145
+ $ newStatus = OrderStatuses::STATUS_CODE_PAID_CORRECTLY ;
143
146
144
147
break ;
145
148
case 'PartiallyPaid ' :
146
149
// TODO This is tricky because we don't know which items were paid and which items not. So how can we know what to invoice?
150
+ break ;
147
151
case 'Voided ' :
148
152
// TODO What should we do? Cancel the order?
149
- case 'Authorized ' :
150
- // TODO Should we do something or just wait for another status?
153
+ break ;
151
154
default :
152
- $ this ->logger ->log ('Unsupported status " ' . $ status . '" for payment request ID ' . $ paymentRequestId );
155
+ $ this ->logger ->log ('Unsupported status " ' . $ status . '" for payment request ID ' . $ paymentRequest ['id ' ]);
156
+ }
157
+
158
+ if ($ isPaid && $ newStatus && $ order ->getTotalDue () > 0 ) {
159
+
160
+ if ($ newStatus !== $ order ->getStatus ()) {
161
+ if ($ createInvoice ) {
162
+ $ msg = 'Customer paid ' . $ paymentRequest ['amount ' ] . ' ' . $ paymentRequest ['currency ' ] . ' using the NoFrixion payment request with ID ' . $ paymentRequest ['id ' ];
163
+ } else {
164
+ $ msg = 'Customer authorized ' . $ paymentRequest ['amount ' ] . ' ' . $ paymentRequest ['currency ' ] . ' using the NoFrixion payment request with ID ' . $ paymentRequest ['id ' ];
165
+ }
166
+ $ order ->addCommentToStatusHistory ($ msg , $ newStatus , true );
167
+
168
+ // Magento bugfix: Set the matching "state" on the order. Apparently Magento does not automatically set the "state" when the "status" changes.
169
+ $ this ->fixOrderState ($ order );
170
+ }
171
+
172
+ $ saveTransaction = $ this ->transactionFactory ->create ();
173
+
174
+ if ($ createInvoice ) {
175
+ $ invoice = $ order ->prepareInvoice ();
176
+ $ invoice ->setRequestedCaptureCase (Invoice::CAPTURE_ONLINE );
177
+
178
+ // We need to set this so the "Refund" button appears when creating a credit memo for an invoice.
179
+ // Refunds only work when creating a credit memo for an invoice. Creating a credit memo for an order (and not a specific invoice) will not show the "Refund" button. Only the "Refund Offline" button will show.
180
+ $ invoice ->setTransactionId ($ paymentRequest ['id ' ]);
181
+
182
+ $ invoice ->register ();
183
+ $ saveTransaction ->addObject ($ invoice );
184
+ }
185
+
186
+ $ saveTransaction ->addObject ($ order );
187
+ $ saveTransaction ->save ();
153
188
}
154
189
190
+
155
191
return $ order ;
156
192
}
157
193
@@ -195,4 +231,34 @@ public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount)
195
231
}
196
232
197
233
234
+ public function addNewStatusToState (string $ state , array $ statusData ): void
235
+ {
236
+ /* @var StatusResource $statusResource */
237
+ $ statusResource = $ this ->statusResourceFactory ->create ();
238
+ $ status = $ this ->statusFactory ->create ();
239
+ $ status ->setData ($ statusData );
240
+ try {
241
+ $ statusResource ->save ($ status );
242
+ } catch (AlreadyExistsException $ exception ) {
243
+ return ;
244
+ }
245
+ $ status ->assignState ($ state , false , true );
246
+ }
247
+
248
+ private function fixOrderState (OrderInterface $ order ): void
249
+ {
250
+ $ status = $ order ->getStatus ();
251
+
252
+ /* @var $statusCollection \Magento\Sales\Model\ResourceModel\Order\Status\Collection\Interceptor */
253
+ $ statusCollection = $ this ->statusCollectionFactory ->create ();
254
+ $ statusCollection ->joinStates ();
255
+ $ statusCollection ->addFieldToFilter ('main_table.status ' , $ status );
256
+
257
+ if ($ statusCollection ->count () === 1 ) {
258
+ $ newState = $ statusCollection ->getFirstItem ()->getState ();
259
+ $ order ->setState ($ newState );
260
+ }
261
+ }
262
+
263
+
198
264
}
0 commit comments