fix: fix paypal payment provider and refactor payment code (#2159)

* feat: support paypal payment provider

* feat: support paypal flow

* feat: use owner replace org for payment

* feat: update paypal logic

* feat: gofumpt

* feat: update payment

* fix: fix notify

* feat: delete log
This commit is contained in:
haiwu
2023-07-30 11:54:42 +08:00
committed by GitHub
parent 026fb207b3
commit eefa1e6df4
29 changed files with 353 additions and 172 deletions

View File

@ -643,8 +643,8 @@ class App extends Component {
<Route exact path="/products/:organizationName/:productName" render={(props) => this.renderLoginIfNotLoggedIn(<ProductEditPage account={this.state.account} {...props} />)} />
<Route exact path="/products/:organizationName/:productName/buy" render={(props) => this.renderLoginIfNotLoggedIn(<ProductBuyPage account={this.state.account} {...props} />)} />
<Route exact path="/payments" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentListPage account={this.state.account} {...props} />)} />
<Route exact path="/payments/:paymentName" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentEditPage account={this.state.account} {...props} />)} />
<Route exact path="/payments/:paymentName/result" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentResultPage account={this.state.account} {...props} />)} />
<Route exact path="/payments/:organizationName/:paymentName" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentEditPage account={this.state.account} {...props} />)} />
<Route exact path="/payments/:organizationName/:paymentName/result" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentResultPage account={this.state.account} {...props} />)} />
<Route exact path="/records" render={(props) => this.renderLoginIfNotLoggedIn(<RecordListPage account={this.state.account} {...props} />)} />
<Route exact path="/mfa/setup" render={(props) => this.renderLoginIfNotLoggedIn(<MfaSetupPage account={this.state.account} onfinish={() => this.setState({requiredEnableMfa: false})} {...props} />)} />
<Route exact path="/.well-known/openid-configuration" render={(props) => <OdicDiscoveryPage />} />

View File

@ -40,7 +40,7 @@ class PaymentEditPage extends React.Component {
}
getPayment() {
PaymentBackend.getPayment("admin", this.state.paymentName)
PaymentBackend.getPayment(this.state.organizationName, this.state.paymentName)
.then((res) => {
if (res.data === null) {
this.props.history.push("/404");

View File

@ -28,13 +28,12 @@ class PaymentListPage extends BaseListPage {
const randomName = Setting.getRandomName();
const organizationName = Setting.getRequestOrganization(this.props.account);
return {
owner: "admin",
owner: organizationName,
name: `payment_${randomName}`,
createdTime: moment().format(),
displayName: `New Payment - ${randomName}`,
provider: "provider_pay_paypal",
type: "PayPal",
organization: organizationName,
user: "admin",
productName: "computer-1",
productDisplayName: "A notebook computer",
@ -54,7 +53,7 @@ class PaymentListPage extends BaseListPage {
PaymentBackend.addPayment(newPayment)
.then((res) => {
if (res.status === "ok") {
this.props.history.push({pathname: `/payments/${newPayment.name}`, mode: "add"});
this.props.history.push({pathname: `/payments/${newPayment.owner}/${newPayment.name}`, mode: "add"});
Setting.showMessage("success", i18next.t("general:Successfully added"));
} else {
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
@ -96,7 +95,7 @@ class PaymentListPage extends BaseListPage {
...this.getColumnSearchProps("name"),
render: (text, record, index) => {
return (
<Link to={`/payments/${text}`}>
<Link to={`/payments/${record.owner}/${text}`}>
{text}
</Link>
);
@ -112,7 +111,7 @@ class PaymentListPage extends BaseListPage {
...this.getColumnSearchProps("provider"),
render: (text, record, index) => {
return (
<Link to={`/providers/${text}`}>
<Link to={`/providers/${record.owner}/${text}`}>
{text}
</Link>
);
@ -120,11 +119,11 @@ class PaymentListPage extends BaseListPage {
},
{
title: i18next.t("general:Organization"),
dataIndex: "organization",
key: "organization",
dataIndex: "owner",
key: "owner",
width: "120px",
sorter: true,
...this.getColumnSearchProps("organization"),
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
@ -142,7 +141,7 @@ class PaymentListPage extends BaseListPage {
...this.getColumnSearchProps("user"),
render: (text, record, index) => {
return (
<Link to={`/users/${record.organization}/${text}`}>
<Link to={`/users/${record.owner}/${text}`}>
{text}
</Link>
);
@ -222,8 +221,8 @@ class PaymentListPage extends BaseListPage {
render: (text, record, index) => {
return (
<div>
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} onClick={() => this.props.history.push(`/payments/${record.name}/result`)}>{i18next.t("payment:Result")}</Button>
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/payments/${record.name}`)}>{i18next.t("general:Edit")}</Button>
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} onClick={() => this.props.history.push(`/payments/${record.owner}/${record.name}/result`)}>{i18next.t("payment:Result")}</Button>
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/payments/${record.owner}/${record.name}`)}>{i18next.t("general:Edit")}</Button>
<PopconfirmModal
title={i18next.t("general:Sure to delete") + `: ${record.name} ?`}
onConfirm={() => this.deletePayment(index)}
@ -266,7 +265,7 @@ class PaymentListPage extends BaseListPage {
value = params.type;
}
this.setState({loading: true});
PaymentBackend.getPayments("admin", Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
PaymentBackend.getPayments(Setting.getRequestOrganization(this.props.account), Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
.then((res) => {
this.setState({
loading: false,

View File

@ -24,6 +24,7 @@ class PaymentResultPage extends React.Component {
this.state = {
classes: props,
paymentName: props.match.params.paymentName,
organizationName: props.match.params.organizationName,
payment: null,
timeout: null,
};
@ -40,18 +41,37 @@ class PaymentResultPage extends React.Component {
}
getPayment() {
PaymentBackend.getPayment("admin", this.state.paymentName)
PaymentBackend.getPayment(this.state.organizationName, this.state.paymentName)
.then((res) => {
this.setState({
payment: res.data,
});
// window.console.log("payment=", res.data);
if (res.data.state === "Created") {
this.setState({timeout: setTimeout(() => this.getPayment(), 1000)});
if (res.data.type === "PayPal") {
this.setState({
timeout: setTimeout(() => {
PaymentBackend.notifyPayment(this.state.organizationName, this.state.paymentName)
.then((res) => {
this.getPayment();
});
}, 1000),
});
} else {
this.setState({timeout: setTimeout(() => this.getPayment(), 1000)});
}
}
});
}
goToPaymentUrl(payment) {
if (payment.returnUrl === undefined || payment.returnUrl === null || payment.returnUrl === "") {
Setting.goToLink(`${window.location.origin}/products/${payment.owner}/${payment.productName}/buy`);
} else {
Setting.goToLink(payment.returnUrl);
}
}
render() {
const payment = this.state.payment;
@ -71,7 +91,7 @@ class PaymentResultPage extends React.Component {
subTitle={i18next.t("payment:Please click the below button to return to the original website")}
extra={[
<Button type="primary" key="returnUrl" onClick={() => {
Setting.goToLink(payment.returnUrl);
this.goToPaymentUrl(payment);
}}>
{i18next.t("payment:Return to Website")}
</Button>,
@ -107,7 +127,7 @@ class PaymentResultPage extends React.Component {
subTitle={i18next.t("payment:Please click the below button to return to the original website")}
extra={[
<Button type="primary" key="returnUrl" onClick={() => {
Setting.goToLink(payment.returnUrl);
this.goToPaymentUrl(payment);
}}>
{i18next.t("payment:Return to Website")}
</Button>,

View File

@ -24,7 +24,8 @@ class ProductBuyPage extends React.Component {
super(props);
this.state = {
classes: props,
productName: props.match?.params.productName,
organizationName: props.organizationName !== undefined ? props.organizationName : props?.match?.params?.organizationName,
productName: props.productName !== undefined ? props.productName : props?.match?.params?.productName,
product: null,
isPlacingOrder: false,
qrCodeModalProvider: null,
@ -36,17 +37,15 @@ class ProductBuyPage extends React.Component {
}
getProduct() {
if (this.state.productName === undefined) {
return;
if (this.state.productName === undefined || this.state.organizationName === undefined) {
return ;
}
ProductBackend.getProduct(this.props.account.owner, this.state.productName)
ProductBackend.getProduct(this.state.organizationName, this.state.productName)
.then((res) => {
if (res.status === "error") {
Setting.showMessage("error", res.msg);
return;
}
this.setState({
product: res.data,
});
@ -97,7 +96,7 @@ class ProductBuyPage extends React.Component {
isPlacingOrder: true,
});
ProductBackend.buyProduct(this.state.product.owner, this.state.productName, provider.name)
ProductBackend.buyProduct(product.owner, product.name, provider.name)
.then((res) => {
if (res.status === "ok") {
const payUrl = res.data;

View File

@ -102,6 +102,13 @@ class ProductListPage extends BaseListPage {
width: "150px",
sorter: true,
...this.getColumnSearchProps("owner"),
render: (text, record, index) => {
return (
<Link to={`/organizations/${text}`}>
{text}
</Link>
);
},
},
{
title: i18next.t("general:Created time"),
@ -189,6 +196,7 @@ class ProductListPage extends BaseListPage {
width: "500px",
...this.getColumnSearchProps("providers"),
render: (text, record, index) => {
const providerOwner = record.owner;
const providers = text;
if (providers.length === 0) {
return `(${i18next.t("general:empty")})`;
@ -207,9 +215,9 @@ class ProductListPage extends BaseListPage {
<List.Item>
<div style={{display: "inline"}}>
<Tooltip placement="topLeft" title="Edit">
<Button style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => Setting.goToLinkSoft(this, `/providers/${providerName}`)} />
<Button style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => Setting.goToLinkSoft(this, `/providers/${providerOwner}/${providerName}`)} />
</Tooltip>
<Link to={`/providers/${providerName}`}>
<Link to={`/providers/${providerOwner}/${providerName}`}>
{providerName}
</Link>
</div>

View File

@ -79,3 +79,13 @@ export function invoicePayment(owner, name) {
},
}).then(res => res.json());
}
export function notifyPayment(owner, name) {
return fetch(`${Setting.ServerUrl}/api/notify-payment/${owner}/${name}`, {
method: "POST",
credentials: "include",
headers: {
"Accept-Language": Setting.getAcceptLanguage(),
},
}).then(res => res.json());
}

View File

@ -152,6 +152,10 @@
"Sending": "Sendet",
"Submit and complete": "Einreichen und abschließen"
},
"enforcer": {
"Edit Enforcer": "Edit Enforcer",
"New Enforcer": "New Enforcer"
},
"forget": {
"Account": "Konto",
"Change Password": "Passwort ändern",
@ -215,6 +219,7 @@
"Enable": "Enable",
"Enabled": "Enabled",
"Enabled successfully": "Enabled successfully",
"Enforcers": "Enforcers",
"Failed to add": "Fehler beim hinzufügen",
"Failed to connect to server": "Die Verbindung zum Server konnte nicht hergestellt werden",
"Failed to delete": "Konnte nicht gelöscht werden",

View File

@ -152,6 +152,10 @@
"Sending": "Sending",
"Submit and complete": "Submit and complete"
},
"enforcer": {
"Edit Enforcer": "Edit Enforcer",
"New Enforcer": "New Enforcer"
},
"forget": {
"Account": "Account",
"Change Password": "Change Password",
@ -215,6 +219,7 @@
"Enable": "Enable",
"Enabled": "Enabled",
"Enabled successfully": "Enabled successfully",
"Enforcers": "Enforcers",
"Failed to add": "Failed to add",
"Failed to connect to server": "Failed to connect to server",
"Failed to delete": "Failed to delete",

View File

@ -152,6 +152,10 @@
"Sending": "Envío",
"Submit and complete": "Enviar y completar"
},
"enforcer": {
"Edit Enforcer": "Edit Enforcer",
"New Enforcer": "New Enforcer"
},
"forget": {
"Account": "Cuenta",
"Change Password": "Cambiar contraseña",
@ -215,6 +219,7 @@
"Enable": "Enable",
"Enabled": "Enabled",
"Enabled successfully": "Enabled successfully",
"Enforcers": "Enforcers",
"Failed to add": "No se pudo agregar",
"Failed to connect to server": "No se pudo conectar al servidor",
"Failed to delete": "No se pudo eliminar",

View File

@ -152,6 +152,10 @@
"Sending": "Envoi",
"Submit and complete": "Soumettre et compléter"
},
"enforcer": {
"Edit Enforcer": "Edit Enforcer",
"New Enforcer": "New Enforcer"
},
"forget": {
"Account": "Compte",
"Change Password": "Changer le mot de passe",
@ -215,6 +219,7 @@
"Enable": "Enable",
"Enabled": "Enabled",
"Enabled successfully": "Enabled successfully",
"Enforcers": "Enforcers",
"Failed to add": "Échec d'ajout",
"Failed to connect to server": "Échec de la connexion au serveur",
"Failed to delete": "Échec de la suppression",

View File

@ -152,6 +152,10 @@
"Sending": "Mengirimkan",
"Submit and complete": "Kirim dan selesaikan"
},
"enforcer": {
"Edit Enforcer": "Edit Enforcer",
"New Enforcer": "New Enforcer"
},
"forget": {
"Account": "Akun",
"Change Password": "Ubah Kata Sandi",
@ -215,6 +219,7 @@
"Enable": "Enable",
"Enabled": "Enabled",
"Enabled successfully": "Enabled successfully",
"Enforcers": "Enforcers",
"Failed to add": "Gagal menambahkan",
"Failed to connect to server": "Gagal terhubung ke server",
"Failed to delete": "Gagal menghapus",

View File

@ -152,6 +152,10 @@
"Sending": "送信",
"Submit and complete": "提出して完了してください"
},
"enforcer": {
"Edit Enforcer": "Edit Enforcer",
"New Enforcer": "New Enforcer"
},
"forget": {
"Account": "アカウント",
"Change Password": "パスワードを変更",
@ -215,6 +219,7 @@
"Enable": "Enable",
"Enabled": "Enabled",
"Enabled successfully": "Enabled successfully",
"Enforcers": "Enforcers",
"Failed to add": "追加できませんでした",
"Failed to connect to server": "サーバーに接続できませんでした",
"Failed to delete": "削除に失敗しました",

View File

@ -152,6 +152,10 @@
"Sending": "전송하기",
"Submit and complete": "제출하고 완료하십시오"
},
"enforcer": {
"Edit Enforcer": "Edit Enforcer",
"New Enforcer": "New Enforcer"
},
"forget": {
"Account": "계정",
"Change Password": "비밀번호 변경",
@ -215,6 +219,7 @@
"Enable": "Enable",
"Enabled": "Enabled",
"Enabled successfully": "Enabled successfully",
"Enforcers": "Enforcers",
"Failed to add": "추가하지 못했습니다",
"Failed to connect to server": "서버에 연결하지 못했습니다",
"Failed to delete": "삭제에 실패했습니다",

View File

@ -152,6 +152,10 @@
"Sending": "Enviando",
"Submit and complete": "Enviar e concluir"
},
"enforcer": {
"Edit Enforcer": "Edit Enforcer",
"New Enforcer": "New Enforcer"
},
"forget": {
"Account": "Conta",
"Change Password": "Alterar Senha",
@ -215,6 +219,7 @@
"Enable": "Habilitar",
"Enabled": "Habilitado",
"Enabled successfully": "Habilitado com sucesso",
"Enforcers": "Enforcers",
"Failed to add": "Falha ao adicionar",
"Failed to connect to server": "Falha ao conectar ao servidor",
"Failed to delete": "Falha ao excluir",

View File

@ -152,6 +152,10 @@
"Sending": "Отправка",
"Submit and complete": "Отправить и завершить"
},
"enforcer": {
"Edit Enforcer": "Edit Enforcer",
"New Enforcer": "New Enforcer"
},
"forget": {
"Account": "Счет",
"Change Password": "Изменить пароль",
@ -215,6 +219,7 @@
"Enable": "Enable",
"Enabled": "Enabled",
"Enabled successfully": "Enabled successfully",
"Enforcers": "Enforcers",
"Failed to add": "Не удалось добавить",
"Failed to connect to server": "Не удалось подключиться к серверу",
"Failed to delete": "Не удалось удалить",

View File

@ -152,6 +152,10 @@
"Sending": "Gửi",
"Submit and complete": "Nộp và hoàn thành"
},
"enforcer": {
"Edit Enforcer": "Edit Enforcer",
"New Enforcer": "New Enforcer"
},
"forget": {
"Account": "Tài khoản",
"Change Password": "Đổi mật khẩu",
@ -215,6 +219,7 @@
"Enable": "Enable",
"Enabled": "Enabled",
"Enabled successfully": "Enabled successfully",
"Enforcers": "Enforcers",
"Failed to add": "Không thể thêm được",
"Failed to connect to server": "Không thể kết nối đến máy chủ",
"Failed to delete": "Không thể xoá",

View File

@ -152,6 +152,10 @@
"Sending": "发送中",
"Submit and complete": "完成提交"
},
"enforcer": {
"Edit Enforcer": "Edit Enforcer",
"New Enforcer": "New Enforcer"
},
"forget": {
"Account": "账号",
"Change Password": "修改密码",
@ -215,6 +219,7 @@
"Enable": "启用",
"Enabled": "已开启",
"Enabled successfully": "启用成功",
"Enforcers": "Enforcers",
"Failed to add": "添加失败",
"Failed to connect to server": "连接服务器失败",
"Failed to delete": "删除失败",