我试图在Angular 6中将[PayPal的JavaScript代码用于其www.sandbox.paypal.com网站1},但收到以下错误消息:
Error: Request to post https://www.sandbox.paypal.com/v1/payments/payment failed with 400 error. Correlation id: 6c0ce47611849, 6c0ce47611849
{
"name": "VALIDATION_ERROR",
"details": [
{
"field": "transactions.amount",
"issue": "Currency amount must be non-negative number, may optionally contain exactly 2 decimal places separated by '.', optional thousands separator ',', limited to 7 digits before the decimal point and currency which is a valid ISO Currency Code"
}
],
"message": "Invalid request - see details",
"information_link": "https://developer.paypal.com/docs/api/payments/#errors",
"debug_id": "6c0ce47611849"
}
request/</<@https://www.paypalobjects.com/api/checkout.js:14216:39
如下面的屏幕截图所示,该格式对我来说是正确的:
以下是我的运送表格html:
<div class="container">
<div class="row">
<div class="col-md-8 order-md-1">
<h4 class="mb-3">Shipping address</h4>
<form name="form" #f="ngForm" novalidate>
<div class="row">
<div class="col-md-6 mb-3">
<label for="firstName">First name</label>
<input
type="text"
class="form-control"
[(ngModel)]="model.firstName"
#firstName="ngModel"
[ngClass]="{
'is-invalid': f.submitted && firstName.invalid
}"
name="firstName"
placeholder="First name"
required
/>
<div
*ngIf="f.submitted && firstName.required"
class="invalid-feedback"
>
<div *ngIf="firstName.errors.required">
First name is required
</div>
</div>
</div>
<div class="col-md-6 mb-3">
<label for="lastName">Last name</label>
<input
type="text"
class="form-control"
[(ngModel)]="model.lastName"
#lastName="ngModel"
[ngClass]="{
'is-invalid': f.submitted && lastName.invalid
}"
name="lastName"
placeholder="Last name"
required
/>
<div
*ngIf="f.submitted && lastName.required"
class="invalid-feedback"
>
<div *ngIf="lastName.errors.required">Last name is required</div>
</div>
</div>
</div>
<div class="mb-3">
<label for="email"
>Email <span class="text-muted">(Same as username)</span></label
>
<input
type="email"
class="form-control"
[(ngModel)]="model.email"
#email="ngModel"
[ngClass]="{
'is-invalid': f.submitted && email.invalid
}"
name="email"
placeholder="you@example.com"
required
value="{{ model.email }}"
email
/>
<div *ngIf="f.submitted && email.required" class="invalid-feedback">
<div *ngIf="email.errors.email">Email is required</div>
</div>
</div>
<div class="mb-3">
<label for="address">Address</label>
<input
type="text"
class="form-control"
[(ngModel)]="model.address"
#address="ngModel"
[ngClass]="{
'is-invalid': f.submitted && address.invalid
}"
name="address"
placeholder="1234 Main St"
required
/>
<div *ngIf="f.submitted && address.required" class="invalid-feedback">
<div *ngIf="address.errors.required">
Shipping address is required
</div>
</div>
</div>
<div class="mb-3">
<label for="address2"
>Address 2 <span class="text-muted">(Optional)</span></label
>
<input
type="text"
class="form-control"
[(ngModel)]="model.address2"
name="address2"
placeholder="Apartment or suite"
#address2="ngModel"
/>
</div>
<div class="mb-3">
<label for="city">City <span class="text-muted"></span></label>
<input
type="text"
class="form-control"
[(ngModel)]="model.city"
name="city"
placeholder="Apartment or suite"
#city="ngModel"
/>
</div>
<div class="mb-3">
<label for="phone">Phone <span class="text-muted"></span></label>
<input
type="text"
class="form-control"
[(ngModel)]="model.phone"
name="phone"
placeholder="Apartment or suite"
#phone="ngModel"
/>
</div>
<div class="row">
<div class="col-md-5 mb-3">
<label for="country">Country</label>
<select
class="custom-select d-block w-100"
[(ngModel)]="model.country"
[ngClass]="{
'is-invalid': f.submitted && country.invalid
}"
name="country"
#country="ngModel"
required
>
<option value="" selected="selected"
>Please choose a country</option
>
<option
*ngFor="let country of countriesObj"
value="{{ country.code }}"
>{{ country.name }}</option
>
</select>
<div
*ngIf="f.submitted && country.required"
class="invalid-feedback"
>
<div *ngIf="country.errors.required">Country is required</div>
</div>
</div>
<div class="mb-3">
<label for="state">State/Province</label>
<input
type="text"
class="form-control"
[(ngModel)]="model.state"
[ngClass]="{
'is-invalid': f.submitted && state.invalid
}"
name="state"
placeholder="California"
#state="ngModel"
required
/>
<div *ngIf="f.submitted && state.required" class="invalid-feedback">
<div *ngIf="state.errors.required">
State/Province is required
</div>
</div>
</div>
<div class="col-md-3 mb-3">
<label for="zip">Zip/Postal Code</label>
<input
type="text"
class="form-control"
[(ngModel)]="model.zip"
[ngClass]="{
'is-invalid': f.submitted && zip.invalid
}"
name="zip"
placeholder="Zip/Postal code"
#zip="ngModel"
required
/>
<div *ngIf="f.submitted && zip.required" class="invalid-feedback">
<div *ngIf="zip.errors.required">Zip/Postal code is required</div>
</div>
</div>
</div>
<hr class="mb-4" />
<h4 class="mb-3">Payment</h4>
<div id="paypal-button-container"></div>
<input
type="text"
[(ngModel)]="model.total"
style="padding-bottom: 10px;"
name="total"
#total="ngModel"
value="{{ model.total | currency }}"
/>
<h2 *ngIf="paypalLoad">Paypal button is loading</h2>
<div id="paypal-checkout-btn"></div>
</form>
</div>
</div>
</div>
<div class="ModalBackdrop"></div>
Final amount: {{ this.finalAmount }}
<!-- The Modal -->
<div class="modal" id="myModal">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header">
<h4 class="modal-title">Thank you</h4>
<button type="button" class="close" data-dismiss="modal">
×
</button>
</div>
<!-- Modal body -->
<div class="modal-body">
This is confirmation that your payment has been processed. Your order
will shipped as soon as possible.
</div>
<!-- Modal footer -->
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal" onclick="document.getElementById('ModalBackdrop').style.display = 'none';">
Close
</button>
</div>
</div>
</div>
</div>
以下是我的运输表单组件-如您所见,我尝试了一些不同的操作:
import { Component, OnInit, AfterViewChecked } from "@angular/core";
import { HttpClient, HttpHeaders, HttpResponse } from "@angular/common/http";
import { ShoppingCartService } from "../shopping-cart.service";
import { ProductService } from "../product.service";
import { LoginService } from "../login.service";
import { modelGroupProvider } from "@angular/forms/src/directives/ng_model_group";
declare let paypal: any;
@Component({
selector: "app-shipping-form",
templateUrl: "./shipping-form.component.html",
styleUrls: ["./shipping-form.component.css"]
})
export class ShippingFormComponent implements OnInit, AfterViewChecked {
public countriesObj;
total;
public model: any = {};
firstName = "";
lastName = "";
email = this.loginSrvc.loginObj.uName;
address = "";
address2 = "";
city = "";
phone = "";
country = "";
state = "";
zip = "";
name = "";
shoppingCartObj: any;
user_id = "";
orders_id = "";
product = "";
ts = "";
constructor(
private http: HttpClient,
private loginSrvc: LoginService,
private prdSrvc: ProductService,
private cartSrvc: ShoppingCartService
) {
this.http.get("./assets/countries.json").subscribe(result => {
this.countriesObj = result;
});
this.total = this.prdSrvc.getPriceTotal();
this.model.total = this.total.toFixed(2);
this.model.email = this.loginSrvc.loginObj.uName;
// this.model.firstName = this.firstName;
// this.model.lastName = this.lastName;
this.name = this.model.firstName + " " + this.model.lastName;
this.email = this.model.email;
this.address = this.model.address;
this.address2 = this.model.address2;
this.city = this.model.city;
this.state = this.model.state;
this.country = this.model.country;
this.zip = this.model.zip;
this.shoppingCartObj = JSON.parse(localStorage.getItem("fh_cart"));
this.user_id = this.shoppingCartObj.cart.user_id;
this.orders_id = this.shoppingCartObj.cart.orders_id;
this.product = JSON.stringify(this.shoppingCartObj.cart.products.product);
this.ts = this.shoppingCartObj.cart.ts;
}
addScript = false;
paypalLoad = true;
finalAmount: number = this.getFinalAmount();
paypalConfig = {
env: "sandbox",
client: {
sandbox:
"<my-sandbox-key>",
production: "<your-production-key here>"
},
commit: true,
payment: function(data, actions) {
return actions.payment.create({
transactions: [
{
amount: {
total: this.finalAmount,
currency: "USD",
details: {
subtotal: "30.00",
tax: "0.07",
shipping: "0.03",
handling_fee: "1.00",
shipping_discount: "-1.00",
insurance: "0.01"
}
},
description: "The payment from for-her application.",
/* custom: "90048630024435", */
invoice_number: this.orders_id, // Insert a unique invoice number
payment_options: {
allowed_payment_method: "INSTANT_FUNDING_SOURCE"
},
soft_descriptor: this.user_id,
item_list: {
items: [this.product],
shipping_address: {
recipient_name: this.name,
line1: this.address,
line2: this.address2,
city: this.city,
country_code: this.country,
postal_code: this.zip,
phone: this.phone,
state: this.state,
email: this.email
}
}
}
],
note_to_payer: "Contact us for any questions on your order."
});
},
onAuthorize: (data, actions) => {
return actions.payment.execute().then(payment => {
// Do something when payment is successful.
// window.alert("Thank you for your purchase! You order will be processed and shipped as soon as possible");
document.getElementById("myModal").style.display = "block";
document.getElementById("ModalBackdrop").style.display = "block";
this.cartSrvc.postCart();
});
}
};
ngAfterViewChecked(): void {
if (!this.addScript) {
this.addPaypalScript().then(() => {
paypal.Button.render(this.paypalConfig, "#paypal-checkout-btn");
this.paypalLoad = false;
});
}
}
addPaypalScript() {
this.addScript = true;
return new Promise((resolve, reject) => {
const scripttagElement = document.createElement("script");
scripttagElement.src = "https://www.paypalobjects.com/api/checkout.js";
scripttagElement.onload = resolve;
document.body.appendChild(scripttagElement);
});
}
getFinalAmount() {
this.total = this.prdSrvc.getPriceTotal();
this.model.total = this.total.toFixed(2);
return this.total.toFixed(2);
}
ngOnInit() {}
}
如您所见,除使用动态值外,我遵循了它们的文档。如示例所示,如果我对值进行硬编码,那么我没有错误。为什么会认为finalAmount无效?
由于注释中的@ paulsm4,网络选项卡未显示值,但硬编码值除外:
和往常一样,谢谢您
答案 0 :(得分:0)
我不知道这是否是正确的方法,但是我不再收到原始错误。
首先,我为要发布的相应项目创建了几个隐藏字段,并为每个输入指定了ID-以下是隐藏字段:
<input
type="text"
[(ngModel)]="model.total"
style="padding-bottom: 10px;"
name="total"
id="total"
#total="ngModel"
value="{{ model.total | currency }}"
/>
<input
type="hidden"
name="user_id"
id="user_id"
value="{{ this.user_id }}"
/>
<input
type="hidden"
name="orders_id"
id="orders_id"
value="{{ this.orders_id }}"
/>
<input
type="hidden"
name="product"
id="product"
value="{{ this.product }}"
/>
<input
type="hidden"
name="subTotal"
id="subTotal"
value="{{ this.payPalSrvc.getSubTotal() }}"
/>
第二,我创建了一个单独的PayPalService,以分离功能,并且,我想要这些帖子,并通过我的拦截器将jwt放置在标题中:
import { Injectable } from "@angular/core";
import { HttpClient, HttpHeaders, HttpResponse } from "@angular/common/http";
import { ShoppingCartService } from "./shopping-cart.service";
import { ProductService } from "./product.service";
import { LoginService } from "./login.service";
@Injectable({
providedIn: "root"
})
export class PaypalService {
constructor(
private http: HttpClient,
private loginSrvc: LoginService,
private prdSrvc: ProductService,
private cartSrvc: ShoppingCartService
) {}
addScript = false;
paypalLoad = true;
finalAmount;
subTotal;
paypalConfig = {
env: "sandbox",
client: {
sandbox:
"<my-sandbox-id>",
production: "<your-production-key here>"
},
commit: true,
payment: function(data, actions) {
return actions.payment.create({
transactions: [
{
amount: {
total: document.getElementById("total").value,
currency: "USD",
details: {
subtotal: document.getElementById("subTotal").value,
tax: (document.getElementById("total").value * 0.07).toFixed(2),
shipping: (document.getElementById("total").value * 0.03).toFixed(2),
handling_fee: "1.00",
shipping_discount: "0.00",
insurance: (document.getElementById("total").value * 0.01).toFixed(2)
}
},
description: "The payment from for-her application.",
/* custom: "90048630024435", */
invoice_number: document.getElementById("orders_id").value, // Insert a unique invoice number
payment_options: {
allowed_payment_method: "INSTANT_FUNDING_SOURCE"
},
soft_descriptor: document.getElementById("user_id").value,
item_list: {
items: [document.getElementById("product").value],
shipping_address: {
recipient_name: (document.getElementById("firstName").value + " " + document.getElementById("lastName").value),
line1: document.getElementById("address").value,
line2: document.getElementById("address2").value,
city: document.getElementById("city").value,
country_code: document.getElementById("country").value,
postal_code: document.getElementById("zip").value
phone: document.getElementById("phone").value,
state: document.getElementById("state").value,
email: document.getElementById("email").value
}
}
}
],
note_to_payer: "Contact us for any questions on your order."
});
},
onAuthorize: (data, actions) => {
return actions.payment.execute().then(payment => {
// Do something when payment is successful.
// window.alert("Thank you for your purchase! You order will be processed and shipped as soon as possible");
document.getElementById("myModal").style.display = "block";
document.getElementById("ModalBackdrop").style.display = "block";
this.cartSrvc.postCart();
});
}
};
addPaypalScript() {
this.addScript = true;
return new Promise((resolve, reject) => {
const scripttagElement = document.createElement("script");
scripttagElement.src = "https://www.paypalobjects.com/api/checkout.js";
scripttagElement.onload = resolve;
document.body.appendChild(scripttagElement);
});
}
public getSubTotal() {
this.subTotal = (document.getElementById("total").value) -
((document.getElementById("total").value * 0.07) +
(document.getElementById("total").value * 0.03) +
(document.getElementById("total").value * 0.01) +
1.00);
return this.subTotal.toFixed(2);
}
public getToken(): string {
return localStorage.getItem("jwt");
}
}
当然,现在我有一个错误的格式错误的请求,它位于jsonlint内,并且您可以看到它返回为有效:
但是最主要的是参数/属性正在工作:
如果有人可以告诉我新错误的含义,那么我将不胜感激。
Error: Request to post https://www.sandbox.paypal.com/v1/payments/payment failed with 400 error. Correlation id: f31569c675597, f31569c675597
{
"name": "MALFORMED_REQUEST",
"message": "Incoming JSON request does not map to API request",
"information_link": "https://developer.paypal.com/webapps/developer/docs/api/#MALFORMED_REQUEST",
"debug_id": "f31569c675597"
}
request/</<@https://www.paypalobjects.com/api/checkout.js:14216:39
再次感谢@ paulsm4建议您查看“网络”选项卡下的值,以查看是否实际发布了该值。
答案 1 :(得分:0)
我有完全相同的问题。当我传递硬编码的值并且我也使用Angular 6时,事务工作。我只有类型输入和Paypal按钮的输入。我正在使用这个项目来使用Paypal https://github.com/Enngage/ngx-paypal 这是我的代码:
component.html
<ngx-paypal [config]="payPalConfig"></ngx-paypal>
<input type="number" class="form-control" placeholder="Enter amount" [(ngModel)]="amount"/>
component.ts
import { Component, OnInit, Input } from '@angular/core';
import { PayPalConfig, PayPalEnvironment, PayPalIntegrationType } from 'ngx-paypal';
@Component({
selector: 'app-paypal',
templateUrl: './paypal.component.html',
styleUrls: ['./paypal.component.css']
})
export class PaypalComponent implements OnInit {
amount: number;
public payPalConfig?: PayPalConfig;
ngOnInit(): void {
this.initConfig();
}
private initConfig(): void {
this.payPalConfig = new PayPalConfig(PayPalIntegrationType.ClientSideREST, PayPalEnvironment.Sandbox, {
commit: true,
client: {
sandbox: '...',
},
button: {
label: 'paypal',
layout: 'vertical'
},
onAuthorize: (data, actions) => {
console.log('Authorize');
return undefined;
},
onPaymentComplete: (data, actions) => {
console.log('OnPaymentComplete');
console.log(data);
},
onCancel: (data, actions) => {
console.log('OnCancel');
},
onError: err => {
if (typeof this.amount === 'number') {
console.log('NUMBER !!!!!!!!!!');
} else if (typeof this.amount === 'string') {
console.log('STRING !!!!!!!!!!');
}
console.log('Amount : ' + this.amount);
console.log('OnError : ' + err);
},
onClick: () => {
console.log('onClick');
},
validate: (actions) => {
console.log(actions);
},
experience: {
noShipping: true,
brandName: '...'
},
transactions: [{
amount: {
currency: 'EUR',
total: this.amount
}
}]
});
}
}
感谢您的帮助!