Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/payments/PaymentRequestManager.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "PaymentRequestManager.h"
8
#include "PaymentRequestUtils.h"
9
#include "mozilla/ClearOnShutdown.h"
10
#include "mozilla/dom/ContentChild.h"
11
#include "mozilla/dom/TabChild.h"
12
#include "mozilla/dom/PaymentRequestChild.h"
13
#include "nsContentUtils.h"
14
#include "nsString.h"
15
#include "nsIPrincipal.h"
16
17
namespace mozilla {
18
namespace dom {
19
namespace {
20
21
/*
22
 *  Following Convert* functions are used for convert PaymentRequest structs
23
 *  to transferable structs for IPC.
24
 */
25
nsresult
26
ConvertMethodData(JSContext* aCx,
27
                  const PaymentMethodData& aMethodData,
28
                  IPCPaymentMethodData& aIPCMethodData)
29
0
{
30
0
  NS_ENSURE_ARG_POINTER(aCx);
31
0
  // Convert JSObject to a serialized string
32
0
  nsAutoString serializedData;
33
0
  if (aMethodData.mData.WasPassed()) {
34
0
    JS::RootedObject object(aCx, aMethodData.mData.Value());
35
0
    nsresult rv = SerializeFromJSObject(aCx, object, serializedData);
36
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
37
0
      return rv;
38
0
    }
39
0
  }
40
0
  aIPCMethodData = IPCPaymentMethodData(aMethodData.mSupportedMethods, serializedData);
41
0
  return NS_OK;
42
0
}
43
44
void
45
ConvertCurrencyAmount(const PaymentCurrencyAmount& aAmount,
46
                      IPCPaymentCurrencyAmount& aIPCCurrencyAmount)
47
0
{
48
0
  aIPCCurrencyAmount = IPCPaymentCurrencyAmount(aAmount.mCurrency, aAmount.mValue);
49
0
}
50
51
void
52
ConvertItem(const PaymentItem& aItem, IPCPaymentItem& aIPCItem)
53
0
{
54
0
  uint8_t typeIndex = UINT8_MAX;
55
0
  if (aItem.mType.WasPassed()) {
56
0
    typeIndex = static_cast<uint8_t>(aItem.mType.Value());
57
0
  }
58
0
  nsString type;
59
0
  if (typeIndex < ArrayLength(PaymentItemTypeValues::strings)) {
60
0
    type.AssignASCII(
61
0
      PaymentItemTypeValues::strings[typeIndex].value);
62
0
  }
63
0
  IPCPaymentCurrencyAmount amount;
64
0
  ConvertCurrencyAmount(aItem.mAmount, amount);
65
0
  aIPCItem = IPCPaymentItem(aItem.mLabel, amount, aItem.mPending, type);
66
0
}
67
68
nsresult
69
ConvertModifier(JSContext* aCx,
70
                const PaymentDetailsModifier& aModifier,
71
                IPCPaymentDetailsModifier& aIPCModifier)
72
0
{
73
0
  NS_ENSURE_ARG_POINTER(aCx);
74
0
  // Convert JSObject to a serialized string
75
0
  nsAutoString serializedData;
76
0
  if (aModifier.mData.WasPassed()) {
77
0
    JS::RootedObject object(aCx, aModifier.mData.Value());
78
0
    nsresult rv = SerializeFromJSObject(aCx, object, serializedData);
79
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
80
0
      return rv;
81
0
    }
82
0
  }
83
0
84
0
  IPCPaymentItem total;
85
0
  ConvertItem(aModifier.mTotal, total);
86
0
87
0
  nsTArray<IPCPaymentItem> additionalDisplayItems;
88
0
  if (aModifier.mAdditionalDisplayItems.WasPassed()) {
89
0
    for (const PaymentItem& item : aModifier.mAdditionalDisplayItems.Value()) {
90
0
      IPCPaymentItem displayItem;
91
0
      ConvertItem(item, displayItem);
92
0
      additionalDisplayItems.AppendElement(displayItem);
93
0
    }
94
0
  }
95
0
  aIPCModifier = IPCPaymentDetailsModifier(aModifier.mSupportedMethods,
96
0
                                           total,
97
0
                                           additionalDisplayItems,
98
0
                                           serializedData,
99
0
                                           aModifier.mAdditionalDisplayItems.WasPassed());
100
0
  return NS_OK;
101
0
}
102
103
void
104
ConvertShippingOption(const PaymentShippingOption& aOption,
105
                      IPCPaymentShippingOption& aIPCOption)
106
0
{
107
0
  IPCPaymentCurrencyAmount amount;
108
0
  ConvertCurrencyAmount(aOption.mAmount, amount);
109
0
  aIPCOption = IPCPaymentShippingOption(aOption.mId, aOption.mLabel, amount, aOption.mSelected);
110
0
}
111
112
nsresult
113
ConvertDetailsBase(JSContext* aCx,
114
                   const PaymentDetailsBase& aDetails,
115
                   nsTArray<IPCPaymentItem>& aDisplayItems,
116
                   nsTArray<IPCPaymentShippingOption>& aShippingOptions,
117
                   nsTArray<IPCPaymentDetailsModifier>& aModifiers,
118
                   bool aRequestShipping)
119
0
{
120
0
  NS_ENSURE_ARG_POINTER(aCx);
121
0
  if (aDetails.mDisplayItems.WasPassed()) {
122
0
    for (const PaymentItem& item : aDetails.mDisplayItems.Value()) {
123
0
      IPCPaymentItem displayItem;
124
0
      ConvertItem(item, displayItem);
125
0
      aDisplayItems.AppendElement(displayItem);
126
0
    }
127
0
  }
128
0
  if (aRequestShipping && aDetails.mShippingOptions.WasPassed()) {
129
0
    for (const PaymentShippingOption& option : aDetails.mShippingOptions.Value()) {
130
0
      IPCPaymentShippingOption shippingOption;
131
0
      ConvertShippingOption(option, shippingOption);
132
0
      aShippingOptions.AppendElement(shippingOption);
133
0
    }
134
0
  }
135
0
  if (aDetails.mModifiers.WasPassed()) {
136
0
    for (const PaymentDetailsModifier& modifier : aDetails.mModifiers.Value()) {
137
0
      IPCPaymentDetailsModifier detailsModifier;
138
0
      nsresult rv = ConvertModifier(aCx, modifier, detailsModifier);
139
0
      if (NS_WARN_IF(NS_FAILED(rv))) {
140
0
        return rv;
141
0
      }
142
0
      aModifiers.AppendElement(detailsModifier);
143
0
    }
144
0
  }
145
0
  return NS_OK;
146
0
}
147
148
nsresult
149
ConvertDetailsInit(JSContext* aCx,
150
                   const PaymentDetailsInit& aDetails,
151
                   IPCPaymentDetails& aIPCDetails,
152
                   bool aRequestShipping)
153
0
{
154
0
  NS_ENSURE_ARG_POINTER(aCx);
155
0
  // Convert PaymentDetailsBase members
156
0
  nsTArray<IPCPaymentItem> displayItems;
157
0
  nsTArray<IPCPaymentShippingOption> shippingOptions;
158
0
  nsTArray<IPCPaymentDetailsModifier> modifiers;
159
0
  nsresult rv = ConvertDetailsBase(aCx, aDetails, displayItems, shippingOptions,
160
0
                                   modifiers, aRequestShipping);
161
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
162
0
    return rv;
163
0
  }
164
0
165
0
  // Convert |id|
166
0
  nsAutoString id;
167
0
  if (aDetails.mId.WasPassed()) {
168
0
    id = aDetails.mId.Value();
169
0
  }
170
0
171
0
  // Convert required |total|
172
0
  IPCPaymentItem total;
173
0
  ConvertItem(aDetails.mTotal, total);
174
0
175
0
  aIPCDetails = IPCPaymentDetails(id,
176
0
                                  total,
177
0
                                  displayItems,
178
0
                                  shippingOptions,
179
0
                                  modifiers,
180
0
                                  EmptyString(), // error message
181
0
                                  EmptyString(), // shippingAddressErrors
182
0
                                  EmptyString(), // payerErrors
183
0
                                  EmptyString()); // paymentMethodErrors
184
0
  return NS_OK;
185
0
}
186
187
nsresult
188
ConvertDetailsUpdate(JSContext* aCx,
189
                     const PaymentDetailsUpdate& aDetails,
190
                     IPCPaymentDetails& aIPCDetails,
191
                     bool aRequestShipping)
192
0
{
193
0
  NS_ENSURE_ARG_POINTER(aCx);
194
0
  // Convert PaymentDetailsBase members
195
0
  nsTArray<IPCPaymentItem> displayItems;
196
0
  nsTArray<IPCPaymentShippingOption> shippingOptions;
197
0
  nsTArray<IPCPaymentDetailsModifier> modifiers;
198
0
  nsresult rv = ConvertDetailsBase(aCx, aDetails, displayItems, shippingOptions,
199
0
                                   modifiers, aRequestShipping);
200
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
201
0
    return rv;
202
0
  }
203
0
204
0
  // Convert required |total|
205
0
  IPCPaymentItem total;
206
0
  ConvertItem(aDetails.mTotal, total);
207
0
208
0
  // Convert |error|
209
0
  nsAutoString error;
210
0
  if (aDetails.mError.WasPassed()) {
211
0
    error = aDetails.mError.Value();
212
0
  }
213
0
214
0
  nsAutoString shippingAddressErrors;
215
0
  if (!aDetails.mShippingAddressErrors.ToJSON(shippingAddressErrors)) {
216
0
    return NS_ERROR_FAILURE;
217
0
  }
218
0
219
0
  nsAutoString payerErrors;
220
0
  if (!aDetails.mPayerErrors.ToJSON(payerErrors)) {
221
0
    return NS_ERROR_FAILURE;
222
0
  }
223
0
224
0
  nsAutoString paymentMethodErrors;
225
0
  if (aDetails.mPaymentMethodErrors.WasPassed()) {
226
0
    JS::RootedObject object(aCx, aDetails.mPaymentMethodErrors.Value());
227
0
    nsresult rv = SerializeFromJSObject(aCx, object, paymentMethodErrors);
228
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
229
0
      return rv;
230
0
    }
231
0
  }
232
0
233
0
  aIPCDetails = IPCPaymentDetails(EmptyString(), // id
234
0
                                  total,
235
0
                                  displayItems,
236
0
                                  shippingOptions,
237
0
                                  modifiers,
238
0
                                  error,
239
0
                                  shippingAddressErrors,
240
0
                                  payerErrors,
241
0
                                  paymentMethodErrors);
242
0
  return NS_OK;
243
0
}
244
245
void
246
ConvertOptions(const PaymentOptions& aOptions,
247
               IPCPaymentOptions& aIPCOption)
248
0
{
249
0
  uint8_t shippingTypeIndex = static_cast<uint8_t>(aOptions.mShippingType);
250
0
  nsString shippingType(NS_LITERAL_STRING("shipping"));
251
0
  if (shippingTypeIndex < ArrayLength(PaymentShippingTypeValues::strings)) {
252
0
    shippingType.AssignASCII(
253
0
      PaymentShippingTypeValues::strings[shippingTypeIndex].value);
254
0
  }
255
0
  aIPCOption = IPCPaymentOptions(aOptions.mRequestPayerName,
256
0
                                 aOptions.mRequestPayerEmail,
257
0
                                 aOptions.mRequestPayerPhone,
258
0
                                 aOptions.mRequestShipping,
259
0
                                 shippingType);
260
0
}
261
} // end of namespace
262
263
/* PaymentRequestManager */
264
265
StaticRefPtr<PaymentRequestManager> gPaymentManager;
266
267
PaymentRequestChild*
268
PaymentRequestManager::GetPaymentChild(PaymentRequest* aRequest)
269
0
{
270
0
  MOZ_ASSERT(aRequest);
271
0
272
0
  if (PaymentRequestChild* child = aRequest->GetIPC()) {
273
0
    return child;
274
0
  }
275
0
276
0
  nsPIDOMWindowInner* win = aRequest->GetOwner();
277
0
  NS_ENSURE_TRUE(win, nullptr);
278
0
  TabChild* tabChild = TabChild::GetFrom(win->GetDocShell());
279
0
  NS_ENSURE_TRUE(tabChild, nullptr);
280
0
  nsAutoString requestId;
281
0
  aRequest->GetInternalId(requestId);
282
0
283
0
  PaymentRequestChild* paymentChild = new PaymentRequestChild(aRequest);
284
0
  tabChild->SendPPaymentRequestConstructor(paymentChild);
285
0
286
0
  return paymentChild;
287
0
}
288
289
nsresult
290
PaymentRequestManager::SendRequestPayment(PaymentRequest* aRequest,
291
                                          const IPCPaymentActionRequest& aAction,
292
                                          bool aResponseExpected)
293
0
{
294
0
  PaymentRequestChild* requestChild = GetPaymentChild(aRequest);
295
0
  nsresult rv = requestChild->RequestPayment(aAction);
296
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
297
0
    return rv;
298
0
  }
299
0
300
0
  if (aResponseExpected) {
301
0
    auto count = mActivePayments.LookupForAdd(aRequest);
302
0
    if (count) {
303
0
      count.Data()++;
304
0
    } else {
305
0
      count.OrInsert([]() { return 1; });
306
0
    }
307
0
  }
308
0
  return NS_OK;
309
0
}
310
311
void
312
PaymentRequestManager::NotifyRequestDone(PaymentRequest* aRequest)
313
0
{
314
0
  auto entry = mActivePayments.Lookup(aRequest);
315
0
  MOZ_ASSERT(entry);
316
0
  MOZ_ASSERT(entry.Data() > 0);
317
0
318
0
  uint32_t count = --entry.Data();
319
0
  if (count == 0) {
320
0
    entry.Remove();
321
0
  }
322
0
}
323
324
void
325
PaymentRequestManager::RequestIPCOver(PaymentRequest* aRequest)
326
0
{
327
0
  // This must only be called from ActorDestroy or if we're sure we won't
328
0
  // receive any more IPC for aRequest.
329
0
  mActivePayments.Remove(aRequest);
330
0
}
331
332
already_AddRefed<PaymentRequestManager>
333
PaymentRequestManager::GetSingleton()
334
0
{
335
0
  if (!gPaymentManager) {
336
0
    gPaymentManager = new PaymentRequestManager();
337
0
    ClearOnShutdown(&gPaymentManager);
338
0
  }
339
0
  RefPtr<PaymentRequestManager> manager = gPaymentManager;
340
0
  return manager.forget();
341
0
}
342
343
void
344
GetSelectedShippingOption(const PaymentDetailsBase& aDetails,
345
                          nsAString& aOption)
346
0
{
347
0
  SetDOMStringToNull(aOption);
348
0
  if (!aDetails.mShippingOptions.WasPassed()) {
349
0
    return;
350
0
  }
351
0
352
0
  const Sequence<PaymentShippingOption>& shippingOptions =
353
0
    aDetails.mShippingOptions.Value();
354
0
  for (const PaymentShippingOption& shippingOption : shippingOptions) {
355
0
    // set aOption to last selected option's ID
356
0
    if (shippingOption.mSelected) {
357
0
      aOption = shippingOption.mId;
358
0
    }
359
0
  }
360
0
}
361
362
nsresult
363
PaymentRequestManager::CreatePayment(JSContext* aCx,
364
                                     nsPIDOMWindowInner* aWindow,
365
                                     nsIPrincipal* aTopLevelPrincipal,
366
                                     const Sequence<PaymentMethodData>& aMethodData,
367
                                     const PaymentDetailsInit& aDetails,
368
                                     const PaymentOptions& aOptions,
369
                                     PaymentRequest** aRequest)
370
0
{
371
0
  MOZ_ASSERT(NS_IsMainThread());
372
0
  NS_ENSURE_ARG_POINTER(aCx);
373
0
  NS_ENSURE_ARG_POINTER(aRequest);
374
0
  NS_ENSURE_ARG_POINTER(aTopLevelPrincipal);
375
0
  *aRequest = nullptr;
376
0
  nsresult rv;
377
0
378
0
  RefPtr<PaymentRequest> request = PaymentRequest::CreatePaymentRequest(aWindow, rv);
379
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
380
0
    return rv;
381
0
  }
382
0
  request->SetOptions(aOptions);
383
0
  /*
384
0
   *  Set request's |mId| to details.id if details.id exists.
385
0
   *  Otherwise, set |mId| to internal id.
386
0
   */
387
0
  nsAutoString requestId;
388
0
  if (aDetails.mId.WasPassed() && !aDetails.mId.Value().IsEmpty()) {
389
0
    requestId = aDetails.mId.Value();
390
0
  } else {
391
0
    request->GetInternalId(requestId);
392
0
  }
393
0
  request->SetId(requestId);
394
0
395
0
  /*
396
0
   * Set request's |mShippingType| and |mShippingOption| if shipping is required.
397
0
   * Set request's mShippingOption to last selected option's ID if
398
0
   * details.shippingOptions exists, otherwise set it as null.
399
0
   */
400
0
  nsAutoString shippingOption;
401
0
  SetDOMStringToNull(shippingOption);
402
0
  if (aOptions.mRequestShipping) {
403
0
    request->ShippingWasRequested();
404
0
    request->SetShippingType(
405
0
        Nullable<PaymentShippingType>(aOptions.mShippingType));
406
0
    GetSelectedShippingOption(aDetails, shippingOption);
407
0
  }
408
0
  request->SetShippingOption(shippingOption);
409
0
410
0
411
0
  nsAutoString internalId;
412
0
  request->GetInternalId(internalId);
413
0
414
0
  nsTArray<IPCPaymentMethodData> methodData;
415
0
  for (const PaymentMethodData& data : aMethodData) {
416
0
    IPCPaymentMethodData ipcMethodData;
417
0
    rv = ConvertMethodData(aCx, data, ipcMethodData);
418
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
419
0
      return rv;
420
0
    }
421
0
    methodData.AppendElement(ipcMethodData);
422
0
  }
423
0
424
0
  IPCPaymentDetails details;
425
0
  rv = ConvertDetailsInit(aCx, aDetails, details, aOptions.mRequestShipping);
426
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
427
0
    return rv;
428
0
  }
429
0
430
0
  IPCPaymentOptions options;
431
0
  ConvertOptions(aOptions, options);
432
0
433
0
  IPCPaymentCreateActionRequest action(internalId,
434
0
                                       IPC::Principal(aTopLevelPrincipal),
435
0
                                       methodData,
436
0
                                       details,
437
0
                                       options,
438
0
                                       shippingOption);
439
0
440
0
  rv = SendRequestPayment(request, action, false);
441
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
442
0
    return rv;
443
0
  }
444
0
  request.forget(aRequest);
445
0
  return NS_OK;
446
0
}
447
448
nsresult
449
PaymentRequestManager::CanMakePayment(PaymentRequest* aRequest)
450
0
{
451
0
  nsAutoString requestId;
452
0
  aRequest->GetInternalId(requestId);
453
0
  IPCPaymentCanMakeActionRequest action(requestId);
454
0
455
0
  return SendRequestPayment(aRequest, action);
456
0
}
457
458
nsresult
459
PaymentRequestManager::ShowPayment(PaymentRequest* aRequest)
460
0
{
461
0
  nsresult rv = NS_OK;
462
0
  if (!aRequest->IsUpdating()) {
463
0
    nsAutoString requestId;
464
0
    aRequest->GetInternalId(requestId);
465
0
    IPCPaymentShowActionRequest action(requestId);
466
0
    rv = SendRequestPayment(aRequest, action);
467
0
  }
468
0
  return rv;
469
0
}
470
471
nsresult
472
PaymentRequestManager::AbortPayment(PaymentRequest* aRequest, bool aDeferredShow)
473
0
{
474
0
  nsAutoString requestId;
475
0
  aRequest->GetInternalId(requestId);
476
0
  IPCPaymentAbortActionRequest action(requestId);
477
0
478
0
  // If aDeferredShow is true, then show was called with a promise that was
479
0
  // rejected. In that case, we need to remember that we called show earlier.
480
0
  return SendRequestPayment(aRequest, action, aDeferredShow);
481
0
}
482
483
nsresult
484
PaymentRequestManager::CompletePayment(PaymentRequest* aRequest,
485
                                       const PaymentComplete& aComplete,
486
                                       bool aTimedOut)
487
0
{
488
0
  nsString completeStatusString(NS_LITERAL_STRING("unknown"));
489
0
  if (aTimedOut) {
490
0
    completeStatusString.AssignLiteral("timeout");
491
0
  } else {
492
0
    uint8_t completeIndex = static_cast<uint8_t>(aComplete);
493
0
    if (completeIndex < ArrayLength(PaymentCompleteValues::strings)) {
494
0
      completeStatusString.AssignASCII(
495
0
        PaymentCompleteValues::strings[completeIndex].value);
496
0
    }
497
0
  }
498
0
499
0
  nsAutoString requestId;
500
0
  aRequest->GetInternalId(requestId);
501
0
  IPCPaymentCompleteActionRequest action(requestId, completeStatusString);
502
0
503
0
  return SendRequestPayment(aRequest, action, false);
504
0
}
505
506
nsresult
507
PaymentRequestManager::UpdatePayment(JSContext* aCx,
508
                                     PaymentRequest* aRequest,
509
                                     const PaymentDetailsUpdate& aDetails,
510
                                     bool aRequestShipping,
511
                                     bool aDeferredShow)
512
0
{
513
0
  NS_ENSURE_ARG_POINTER(aCx);
514
0
  IPCPaymentDetails details;
515
0
  nsresult rv = ConvertDetailsUpdate(aCx, aDetails, details, aRequestShipping);
516
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
517
0
    return rv;
518
0
  }
519
0
520
0
  nsAutoString shippingOption;
521
0
  SetDOMStringToNull(shippingOption);
522
0
  if (aRequestShipping) {
523
0
    GetSelectedShippingOption(aDetails, shippingOption);
524
0
    aRequest->SetShippingOption(shippingOption);
525
0
  }
526
0
527
0
  nsAutoString requestId;
528
0
  aRequest->GetInternalId(requestId);
529
0
  IPCPaymentUpdateActionRequest action(requestId, details, shippingOption);
530
0
531
0
  // If aDeferredShow is true, then this call serves as the ShowUpdate call for
532
0
  // this request.
533
0
  return SendRequestPayment(aRequest, action, aDeferredShow);
534
0
}
535
536
nsresult
537
PaymentRequestManager::ClosePayment(PaymentRequest* aRequest)
538
0
{
539
0
  // for the case, the payment request is waiting for response from user.
540
0
  if (auto entry = mActivePayments.Lookup(aRequest)) {
541
0
    NotifyRequestDone(aRequest);
542
0
  }
543
0
  nsAutoString requestId;
544
0
  aRequest->GetInternalId(requestId);
545
0
  IPCPaymentCloseActionRequest action(requestId);
546
0
  return SendRequestPayment(aRequest, action, false);
547
0
}
548
549
nsresult
550
PaymentRequestManager::RetryPayment(JSContext* aCx,
551
                                    PaymentRequest* aRequest,
552
                                    const PaymentValidationErrors& aErrors)
553
0
{
554
0
  NS_ENSURE_ARG_POINTER(aCx);
555
0
  NS_ENSURE_ARG_POINTER(aRequest);
556
0
557
0
  nsAutoString requestId;
558
0
  aRequest->GetInternalId(requestId);
559
0
560
0
  nsAutoString error;
561
0
  if (aErrors.mError.WasPassed()) {
562
0
    error = aErrors.mError.Value();
563
0
  }
564
0
565
0
  nsAutoString shippingAddressErrors;
566
0
  aErrors.mShippingAddress.ToJSON(shippingAddressErrors);
567
0
568
0
  nsAutoString payerErrors;
569
0
  aErrors.mPayer.ToJSON(payerErrors);
570
0
571
0
  nsAutoString paymentMethodErrors;
572
0
  if (aErrors.mPaymentMethod.WasPassed()) {
573
0
    JS::RootedObject object(aCx, aErrors.mPaymentMethod.Value());
574
0
    nsresult rv = SerializeFromJSObject(aCx, object, paymentMethodErrors);
575
0
    if (NS_WARN_IF(NS_FAILED(rv))) {
576
0
      return rv;
577
0
    }
578
0
  }
579
0
  IPCPaymentRetryActionRequest action(requestId,
580
0
                                      error,
581
0
                                      payerErrors,
582
0
                                      paymentMethodErrors,
583
0
                                      shippingAddressErrors);
584
0
  return SendRequestPayment(aRequest, action);
585
0
}
586
587
nsresult
588
PaymentRequestManager::RespondPayment(PaymentRequest* aRequest,
589
                                      const IPCPaymentActionResponse& aResponse)
590
0
{
591
0
  switch (aResponse.type()) {
592
0
    case IPCPaymentActionResponse::TIPCPaymentCanMakeActionResponse: {
593
0
      const IPCPaymentCanMakeActionResponse& response = aResponse;
594
0
      aRequest->RespondCanMakePayment(response.result());
595
0
      NotifyRequestDone(aRequest);
596
0
      break;
597
0
    }
598
0
    case IPCPaymentActionResponse::TIPCPaymentShowActionResponse: {
599
0
      const IPCPaymentShowActionResponse& response = aResponse;
600
0
      nsresult rejectedReason = NS_ERROR_DOM_ABORT_ERR;
601
0
      switch (response.status()) {
602
0
        case nsIPaymentActionResponse::PAYMENT_ACCEPTED: {
603
0
          rejectedReason = NS_OK;
604
0
          break;
605
0
        }
606
0
        case nsIPaymentActionResponse::PAYMENT_REJECTED: {
607
0
          rejectedReason = NS_ERROR_DOM_ABORT_ERR;
608
0
          break;
609
0
        }
610
0
        case nsIPaymentActionResponse::PAYMENT_NOTSUPPORTED: {
611
0
          rejectedReason = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
612
0
          break;
613
0
        }
614
0
        default: {
615
0
          rejectedReason = NS_ERROR_UNEXPECTED;
616
0
          break;
617
0
        }
618
0
      }
619
0
      aRequest->RespondShowPayment(response.methodName(),
620
0
                                   response.data(),
621
0
                                   response.payerName(),
622
0
                                   response.payerEmail(),
623
0
                                   response.payerPhone(),
624
0
                                   rejectedReason);
625
0
      if (NS_FAILED(rejectedReason)) {
626
0
        NotifyRequestDone(aRequest);
627
0
      }
628
0
      break;
629
0
    }
630
0
    case IPCPaymentActionResponse::TIPCPaymentAbortActionResponse: {
631
0
      const IPCPaymentAbortActionResponse& response = aResponse;
632
0
      aRequest->RespondAbortPayment(response.isSucceeded());
633
0
      NotifyRequestDone(aRequest);
634
0
      break;
635
0
    }
636
0
    case IPCPaymentActionResponse::TIPCPaymentCompleteActionResponse: {
637
0
      aRequest->RespondComplete();
638
0
      NotifyRequestDone(aRequest);
639
0
      break;
640
0
    }
641
0
    default: {
642
0
      return NS_ERROR_FAILURE;
643
0
    }
644
0
  }
645
0
  return NS_OK;
646
0
}
647
648
nsresult
649
PaymentRequestManager::ChangeShippingAddress(PaymentRequest* aRequest,
650
                                             const IPCPaymentAddress& aAddress)
651
0
{
652
0
  return aRequest->UpdateShippingAddress(aAddress.country(),
653
0
                                         aAddress.addressLine(),
654
0
                                         aAddress.region(),
655
0
                                         aAddress.city(),
656
0
                                         aAddress.dependentLocality(),
657
0
                                         aAddress.postalCode(),
658
0
                                         aAddress.sortingCode(),
659
0
                                         aAddress.organization(),
660
0
                                         aAddress.recipient(),
661
0
                                         aAddress.phone());
662
0
}
663
664
nsresult
665
PaymentRequestManager::ChangeShippingOption(PaymentRequest* aRequest,
666
                                            const nsAString& aOption)
667
0
{
668
0
  return aRequest->UpdateShippingOption(aOption);
669
0
}
670
671
nsresult
672
PaymentRequestManager::ChangePayerDetail(PaymentRequest* aRequest,
673
                                         const nsAString& aPayerName,
674
                                         const nsAString& aPayerEmail,
675
                                         const nsAString& aPayerPhone)
676
0
{
677
0
  MOZ_ASSERT(aRequest);
678
0
  RefPtr<PaymentResponse> response = aRequest->GetResponse();
679
0
  // ignoring the case call changePayerDetail during show().
680
0
  if (!response) {
681
0
    return NS_OK;
682
0
  }
683
0
  return response->UpdatePayerDetail(aPayerName, aPayerEmail, aPayerPhone);
684
0
}
685
686
} // end of namespace dom
687
} // end of namespace mozilla