diff --git a/src/layout/MainLayout/Header/index.js b/src/layout/MainLayout/Header/index.js
index c2755ef..255e1ff 100644
--- a/src/layout/MainLayout/Header/index.js
+++ b/src/layout/MainLayout/Header/index.js
@@ -516,6 +516,20 @@ function Header(props) {
{isGranted("MAINTAIN_SETTING") ? (
<>
+
+
+
+ HKID Key Migration
+
+
+
+
+
+
+ User PII Encryption
+
+
+
diff --git a/src/pages/Payment/Details_GLD/PaymentDetails.js b/src/pages/Payment/Details_GLD/PaymentDetails.js
index 2c7cd0e..7282f51 100644
--- a/src/pages/Payment/Details_GLD/PaymentDetails.js
+++ b/src/pages/Payment/Details_GLD/PaymentDetails.js
@@ -3,24 +3,33 @@ import {
Grid,
Typography,
FormLabel,
- Button
+ Button,
+ Dialog,
+ DialogTitle,
+ DialogContent,
+ DialogActions,
+ Box
} from '@mui/material';
import * as React from "react";
import * as FormatUtils from "utils/FormatUtils";
import * as PaymentStatus from "utils/statusUtils/PaymentStatus";
import * as DateUtils from "utils/DateUtils";
+import * as HttpUtils from "utils/HttpUtils";
+import { PAYMENT_MARK_AS_PAID } from "utils/ApiPathConst";
import Loadable from 'components/Loadable';
const MainCard = Loadable(React.lazy(() => import('components/MainCard')));
const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/LoadingComponent')));
import DownloadIcon from '@mui/icons-material/Download';
import {useIntl} from "react-intl";
// ==============================|| DASHBOARD - DEFAULT ||============================== //
-const PaymentDetails = ({ formData,doPrint,onDownload }) => {
+const PaymentDetails = ({ formData, doPrint, onDownload, onRefresh }) => {
const intl = useIntl();
const [data, setData] = React.useState({});
const [onReady, setOnReady] = React.useState(false);
+ const [confirmOpen, setConfirmOpen] = React.useState(false);
+ const [markingPaid, setMarkingPaid] = React.useState(false);
// const { locale } = intl;
React.useEffect(() => {
@@ -40,9 +49,29 @@ const PaymentDetails = ({ formData,doPrint,onDownload }) => {
if("01" == paymentmethod) return "PPS";
if("02" == paymentmethod || "03" == paymentmethod) return "Credit Card";
if("04" == paymentmethod) return "FPS";
+ if (data.payMethod === "04,BCFP,FPS") return "FPS";
return paymentmethod;
}
+ const showMarkAsPaid = data.status === "REJT" && getPaymentMethod() === "FPS";
+
+ const handleMarkAsPaid = () => {
+ setMarkingPaid(true);
+ HttpUtils.post({
+ url: PAYMENT_MARK_AS_PAID + "/" + data.id,
+ onSuccess: () => {
+ setConfirmOpen(false);
+ setMarkingPaid(false);
+ if (onRefresh) {
+ onRefresh();
+ }
+ },
+ onError: () => {
+ setMarkingPaid(false);
+ }
+ });
+ };
+
return (
!onReady ?
@@ -51,9 +80,21 @@ const PaymentDetails = ({ formData,doPrint,onDownload }) => {
border={false}
content={false}
>
-
- Payment Details
-
+
+
+ Payment Details
+
+ {showMarkAsPaid && (
+
+ )}
+
+
);
};
diff --git a/src/pages/Payment/Details_GLD/index.js b/src/pages/Payment/Details_GLD/index.js
index b51a182..2934748 100644
--- a/src/pages/Payment/Details_GLD/index.js
+++ b/src/pages/Payment/Details_GLD/index.js
@@ -35,6 +35,9 @@ const Index = () => {
const params = useParams();
const navigate = useNavigate()
+ const [responeData, setResponeData] = React.useState({});
+ const [transactionData, setTransactionData] = React.useState({});
+
const [record, setRecord] = React.useState();
const [itemList, setItemList] = React.useState([]);
const [onReady, setOnReady] = React.useState(false);
@@ -47,8 +50,16 @@ const Index = () => {
}, []);
React.useEffect(() => {
- setOnReady(true);
- }, [record]);
+ if (Object.keys(responeData).length > 0) {
+ setTransactionData(responeData);
+ }
+ }, [responeData]);
+
+ React.useEffect(() => {
+ if (Object.keys(transactionData).length > 0) {
+ setOnReady(true);
+ }
+ }, [transactionData]);
// const handleResize = () => {
// setDetailsOrder(window.innerWidth > 1023 ? 2 : -1);
@@ -70,17 +81,40 @@ const Index = () => {
const loadForm = () => {
if (params.id > 0) {
-
HttpUtils.get({
url: UrlUtils.PAYMENT_LOAD + "/" + params.id,
onSuccess: (responseData) => {
if (!responseData.data?.id) {
navigate("/paymentPage/search");
}
- responseData.data["transDateStr"] = responseData.data.transDateTime;
- responseData.data["transTimeStr"] = DateUtils.dateFormat(responseData.data.transDateTime, "HH:mm:ss");
- setItemList(responseData.paymentItemList)
- setRecord(responseData.data);
+ if (responseData.data.status == null || responseData.data.status == "INPR") {
+ HttpUtils.post({
+ url: UrlUtils.PAYMENT_RETRY_STATUS_API,
+ params: {
+ "paymentId": params.id
+ },
+ onSuccess: function (responseData2) {
+ responseData2.data["transDateStr"] = responseData2.data.transDateTime;
+ responseData2.data["transTimeStr"] = DateUtils.dateFormat(responseData2.data.transDateTime, "HH:mm:ss");
+ setResponeData(responseData2.transactionData);
+ setItemList(responseData2.paymentItemList);
+ setRecord(responseData2.data);
+ },
+ onError: function () {
+ responseData.data["transDateStr"] = responseData.data.transDateTime;
+ responseData.data["transTimeStr"] = DateUtils.dateFormat(responseData.data.transDateTime, "HH:mm:ss");
+ setResponeData(responseData);
+ setItemList(responseData.paymentItemList);
+ setRecord(responseData.data);
+ }
+ });
+ } else {
+ responseData.data["transDateStr"] = responseData.data.transDateTime;
+ responseData.data["transTimeStr"] = DateUtils.dateFormat(responseData.data.transDateTime, "HH:mm:ss");
+ setResponeData(responseData);
+ setItemList(responseData.paymentItemList);
+ setRecord(responseData.data);
+ }
}
});
}
@@ -125,6 +159,7 @@ const Index = () => {
formData={record}
doPrint={doPrint}
onDownload={onDownload}
+ onRefresh={loadForm}
style={{
display: "flex",
height: "100%",
diff --git a/src/pages/Payment/Search_GLD/DataGrid.js b/src/pages/Payment/Search_GLD/DataGrid.js
index d24fed0..f1d9891 100644
--- a/src/pages/Payment/Search_GLD/DataGrid.js
+++ b/src/pages/Payment/Search_GLD/DataGrid.js
@@ -87,7 +87,7 @@ export default function SearchPaymentTable({ searchCriteria, applyGridOnReady, a
},
{
field: 'actions',
- headerName: 'Transaction No.',
+ headerName: 'Payment No.',
flex: 1,
minWidth: 200,
cellClassName: 'actions',
@@ -95,6 +95,12 @@ export default function SearchPaymentTable({ searchCriteria, applyGridOnReady, a
return clickableLink('/paymentPage/details/' + params.row.id, params.row.transNo);
},
},
+ {
+ field: 'egisRefNo',
+ headerName: 'Payment Reference No.',
+ flex: 1,
+ minWidth: 200,
+ },
{
field: 'payMethod',
headerName: 'Payment Method',
@@ -107,7 +113,7 @@ export default function SearchPaymentTable({ searchCriteria, applyGridOnReady, a
{
id: 'transDateTime',
field: 'transDateTime',
- headerName: 'Transaction Date',
+ headerName: 'Payment Date',
flex: 1,
minWidth: 150,
diff --git a/src/pages/Payment/Search_Public/DataGrid.js b/src/pages/Payment/Search_Public/DataGrid.js
index 1e16572..c606e43 100644
--- a/src/pages/Payment/Search_Public/DataGrid.js
+++ b/src/pages/Payment/Search_Public/DataGrid.js
@@ -11,6 +11,7 @@ import { FiDataGrid } from "components/FiDataGrid";
import {useTheme} from "@emotion/react";
import {useIntl} from "react-intl";
import { clickableLink } from 'utils/CommonFunction';
+import { getPaymentMethodByCode } from "auth/utils";
import {PAYMENT_LIST} from "utils/ApiPathConst";
// ==============================|| EVENT TABLE ||============================== //
@@ -58,6 +59,12 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
return clickableLink('/paymentPage/details/' + params.row.id, params.row.transNo);
},
},
+ {
+ field: 'egisRefNo',
+ headerName: intl.formatMessage({id: 'paymentRefCode'}),
+ width: isMdOrLg ? 'auto' : 160,
+ flex: isMdOrLg ? 1 : undefined,
+ },
{
id: 'appNos',
field: 'appNos',
@@ -69,6 +76,13 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
return {appNo}
},
},
+ {
+ field: 'payMethod',
+ headerName: intl.formatMessage({id: 'paymentMethod'}),
+ width: isMdOrLg ? 'auto' : 160,
+ flex: isMdOrLg ? 1 : undefined,
+ renderCell: (params) => getPaymentMethodByCode(params?.value),
+ },
{
id: 'transDateTime',
field: 'transDateTime',
diff --git a/src/pages/Setting/HkidKeyMigration/index.js b/src/pages/Setting/HkidKeyMigration/index.js
new file mode 100644
index 0000000..15d091f
--- /dev/null
+++ b/src/pages/Setting/HkidKeyMigration/index.js
@@ -0,0 +1,101 @@
+import * as React from "react";
+import * as HttpUtils from "utils/HttpUtils";
+import * as DateUtils from "utils/DateUtils";
+import * as UrlUtils from "utils/ApiPathConst";
+
+import {
+ Grid, Typography, Button,
+ Stack, Box, CircularProgress,
+} from '@mui/material';
+import { notifyActionError } from 'utils/CommonFunction';
+
+import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
+
+const formatLog = (responData) => {
+ if (responData?.msg && !responData?.log) {
+ return <>{DateUtils.datetimeStr(new Date())}
Error
{responData.msg}>;
+ }
+ const statusColor = responData?.success ? "green" : "red";
+ const statusText = responData?.success ? "Success" : "Completed with errors";
+ const logText = (responData?.log || []).join("\n");
+ return (
+ <>
+ {DateUtils.datetimeStr(new Date())}
+ {responData?.dryRun ? "Dry-run " : ""}{statusText}
+ Total: {responData?.total ?? 0}, OK: {responData?.successCount ?? 0}, Skipped: {responData?.skipped ?? 0}, Failed: {responData?.failed ?? 0}
+ {logText}
+ >
+ );
+};
+
+const HkidKeyMigration = () => {
+ const [resultStr, setResultStr] = React.useState("");
+ const [wait, setWait] = React.useState(false);
+
+ const BackgroundHead = {
+ backgroundImage: `url(${titleBackgroundImg})`,
+ width: 'auto',
+ height: 'auto',
+ backgroundSize: 'contain',
+ backgroundRepeat: 'no-repeat',
+ backgroundColor: '#0C489E',
+ backgroundPosition: 'right'
+ };
+
+ const runMigration = (dryRun) => {
+ setWait(true);
+ HttpUtils.post({
+ url: `${UrlUtils.HKID_REKEY_MIGRATION}?dryRun=${dryRun}&batchSize=100`,
+ params: {},
+ onSuccess: function (responData) {
+ setWait(false);
+ setResultStr(formatLog(responData));
+ },
+ onError: function () {
+ setWait(false);
+ notifyActionError("HKID re-key migration failed");
+ }
+ });
+ };
+
+ return (
+
+
+
+
+
+ HKID Key Migration
+
+
+
+
+
+
+
+
+ Re-encrypt identification and checkDigit from the legacy key to the new key.
+ Ensure Tomcat has both security.hkid-secret and security.hkid-secret-legacy configured before running.
+
+
+
+
+ {wait ? : null}
+
+
+
+
+
+
+ Result:
+ {resultStr}
+
+
+
+ );
+};
+
+export default HkidKeyMigration;
diff --git a/src/pages/Setting/UserPiiEncryption/index.js b/src/pages/Setting/UserPiiEncryption/index.js
new file mode 100644
index 0000000..e1e17b9
--- /dev/null
+++ b/src/pages/Setting/UserPiiEncryption/index.js
@@ -0,0 +1,133 @@
+import * as React from "react";
+import * as HttpUtils from "utils/HttpUtils";
+import * as DateUtils from "utils/DateUtils";
+import * as UrlUtils from "utils/ApiPathConst";
+
+import {
+ Grid, Typography, Button,
+ Stack, Box, CircularProgress,
+} from '@mui/material';
+import { notifyActionError } from 'utils/CommonFunction';
+
+import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'
+
+const formatEncryptLog = (responData) => {
+ if (responData?.msg && !responData?.log) {
+ return <>{DateUtils.datetimeStr(new Date())}
Error
{responData.msg}>;
+ }
+ const statusColor = responData?.success ? "green" : "red";
+ const statusText = responData?.success ? "Success" : "Completed with errors";
+ const logText = (responData?.log || []).join("\n");
+ return (
+ <>
+ {DateUtils.datetimeStr(new Date())}
+ {responData?.dryRun ? "Dry-run " : ""}{statusText}
+ Total: {responData?.total ?? 0}, OK: {responData?.successCount ?? 0}, Skipped: {responData?.skipped ?? 0}, Failed: {responData?.failed ?? 0}
+ {logText}
+ >
+ );
+};
+
+const formatVerifyLog = (responData) => {
+ const tests = responData?.tests || [];
+ const logText = tests.map(t => `${t.passed ? "PASS" : "FAIL"} - ${t.name}: ${t.message}`).join("\n");
+ const statusColor = responData?.success ? "green" : "red";
+ return (
+ <>
+ {DateUtils.datetimeStr(new Date())}
+ {responData?.success ? "All tests passed" : "Some tests failed"}
+ Passed: {responData?.passed ?? 0}, Failed: {responData?.failed ?? 0}
+ {logText}
+ >
+ );
+};
+
+const UserPiiEncryption = () => {
+ const [resultStr, setResultStr] = React.useState("");
+ const [wait, setWait] = React.useState(false);
+
+ const BackgroundHead = {
+ backgroundImage: `url(${titleBackgroundImg})`,
+ width: 'auto',
+ height: 'auto',
+ backgroundSize: 'contain',
+ backgroundRepeat: 'no-repeat',
+ backgroundColor: '#0C489E',
+ backgroundPosition: 'right'
+ };
+
+ const runEncrypt = (dryRun) => {
+ setWait(true);
+ HttpUtils.post({
+ url: `${UrlUtils.USER_PII_ENCRYPT_MIGRATION}?dryRun=${dryRun}&batchSize=100`,
+ params: {},
+ onSuccess: function (responData) {
+ setWait(false);
+ setResultStr(formatEncryptLog(responData));
+ },
+ onError: function () {
+ setWait(false);
+ notifyActionError("User PII encryption failed");
+ }
+ });
+ };
+
+ const runVerify = () => {
+ setWait(true);
+ HttpUtils.post({
+ url: UrlUtils.USER_PII_VERIFY_MIGRATION,
+ params: {},
+ onSuccess: function (responData) {
+ setWait(false);
+ setResultStr(formatVerifyLog(responData));
+ },
+ onError: function () {
+ setWait(false);
+ notifyActionError("User PII verification failed");
+ }
+ });
+ };
+
+ return (
+
+
+
+
+
+ User PII Encryption
+
+
+
+
+
+
+
+
+ Encrypt enName, chName, mobileNumber, and address for existing user records, then verify data retrieval.
+
+
+
+
+
+ {wait ? : null}
+
+
+
+
+
+
+ Result:
+ {resultStr}
+
+
+
+ );
+};
+
+export default UserPiiEncryption;
diff --git a/src/pages/User/DetailsPage_Individual/UserInformationCard_Individual.js b/src/pages/User/DetailsPage_Individual/UserInformationCard_Individual.js
index 9512edd..0e4fbe8 100644
--- a/src/pages/User/DetailsPage_Individual/UserInformationCard_Individual.js
+++ b/src/pages/User/DetailsPage_Individual/UserInformationCard_Individual.js
@@ -81,7 +81,10 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
addressLine3: yup.string().max(40, getMaxErrStr(40)).nullable(),
emailAddress: yup.string().email(intl.formatMessage({ id: 'validEmailFormat' })).max(255).required(intl.formatMessage({ id: 'requireEmail' })),
idDocType: yup.string().max(255, getMaxErrStr(255)).required(intl.formatMessage({ id: 'requireIdDocType' })),
- identification: yup.string().required(getRequiredErrStr('number'))
+ identification: yup.string().when('verifiedBy', {
+ is: (verifiedBy) => verifiedBy != null,
+ then: (schema) => schema.notRequired(),
+ otherwise: (schema) => schema.required(getRequiredErrStr('number'))
.matches(/^[aA-zZ0-9\s]+$/, { message: displayErrorMsg(`${selectedIdDocInputType}${intl.formatMessage({ id: 'noSpecialCharacter' })}`) })
.matches(/^\S*$/, { message: displayErrorMsg(`${selectedIdDocInputType}${intl.formatMessage({ id: 'noSpace' })}`) })
.test('checkIDCardFormat', displayErrorMsg(`${intl.formatMessage({ id: 'requiredValid' })}${selectedIdDocInputType}${intl.formatMessage({ id: 'number' })}`), function (value) {
@@ -133,8 +136,12 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
break;
}
}
+ })
}),
- checkDigit: yup.string().max(1, getMaxErrStr(1)).nullable()
+ checkDigit: yup.string().when('verifiedBy', {
+ is: (verifiedBy) => verifiedBy != null,
+ then: (schema) => schema.notRequired(),
+ otherwise: (schema) => schema.max(1, getMaxErrStr(1)).nullable()
.matches(/^[A-Z0-9\s]+$/, { message: displayErrorMsg(`${selectedIdDocInputType}${intl.formatMessage({ id: 'noSpecialCharacter' })}`) })
.test('checkIDCardFormat', displayErrorMsg(`${intl.formatMessage({ id: 'requiredNumberInQuote' })}`), function (value) {
// console.log(selectedIdDocInputType)
@@ -162,7 +169,8 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
return false
}
}
- }),
+ })
+ }),
tel_countryCode: yup.string().min(3, intl.formatMessage({ id: 'require3Number' })).required(intl.formatMessage({ id: 'requireDialingCode' })),
fax_countryCode: yup.string().min(3, intl.formatMessage({ id: 'require3Number' })),
phoneNumber: yup.string().min(8, intl.formatMessage({ id: 'require8Number' })).required(intl.formatMessage({ id: 'requireContactNumber' })),
@@ -186,8 +194,10 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
countryCode: values.tel_countryCode,
phoneNumber: values.phoneNumber
},
- identification: values.identification,
- checkDigit: values.checkDigit,
+ ...(values.verifiedBy == null ? {
+ identification: values.identification,
+ checkDigit: values.checkDigit,
+ } : {}),
faxNo: {
countryCode: values.fax_countryCode,
faxNumber: values.faxNumber
@@ -471,6 +481,11 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
+ {currentUserData.verifiedBy ?
+
+ Hidden for security purpose
+
+ :
{formik.values.idDocType === "HKID" ?
editMode ?
@@ -549,6 +564,7 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
}
+ }
diff --git a/src/pages/User/DetailsPage_Individual/UserInformationCard_Individual_Pub.js b/src/pages/User/DetailsPage_Individual/UserInformationCard_Individual_Pub.js
index ca2b791..b350319 100644
--- a/src/pages/User/DetailsPage_Individual/UserInformationCard_Individual_Pub.js
+++ b/src/pages/User/DetailsPage_Individual/UserInformationCard_Individual_Pub.js
@@ -2,8 +2,6 @@
import {
Grid, Button, Typography,
FormHelperText,
- Stack,
- IconButton
} from '@mui/material';
import MainCard from "components/MainCard";
import * as React from "react";
@@ -23,7 +21,6 @@ import { PRIMARY_CONTAINED_BUTTON_SX } from 'themes/colorConst';
import {FormattedMessage, useIntl} from "react-intl";
import {PNSPS_BUTTON_THEME} from "../../../themes/buttonConst";
import {ThemeProvider} from "@emotion/react";
-import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons';
// ==============================|| DASHBOARD - DEFAULT ||============================== //
@@ -34,15 +31,6 @@ const UserInformationCard_Individual_Pub = ({ formData, loadDataFun }) => {
const [editMode, setEditMode] = useState(false);
const [onReady, setOnReady] = useState(false);
const [errorMsg, setErrorMsg] = useState("");
- const [showId, setshowId] = useState(false);
-
- const handleClickShowId = () => {
- setshowId(!showId);
- };
-
- const handleMouseDownId = (event) => {
- event.preventDefault();
- };
useEffect(() => {
if (Object.keys(formData).length > 0) {
@@ -252,79 +240,9 @@ const UserInformationCard_Individual_Pub = ({ formData, loadDataFun }) => {
-
- {formik.values.idDocType === "HKID" ?
- // <>
- //
- // {FieldUtils.initField({
- // valueName: "identification",
- // disabled: true,
- // form: formik,
- // placeholder: intl.formatMessage({id: 'idDocNumber'}),
- // inputProps: {
- // maxLength: 7,
- // onKeyDown: (e) => {
- // if (e.key === 'Enter') {
- // e.preventDefault();
- // }
- // },
- // }
- // })}
-
- //
- //
- // {FieldUtils.initField({
- // valueName: "checkDigit",
- // disabled: true,
- // form: formik,
- // })}
- //
- // >
-
-
- {formik.values.identification?.slice(0, 4)}
-
-
- {/* {showId ?formik.values.identification.slice(4):"****"}{showId ? '(' + formik.values.checkDigit + ')' :null} */}
- {showId ? formik.values.identification?.slice(4) : "****"}{showId ? formik.values.checkDigit?'(' +formik.values.checkDigit+ ')': "()" : ""}
-
-
- {showId ? : }
-
-
- :
- //
- // {FieldUtils.initField({
- // valueName: "identification",
- // disabled: true,
- // form: formik
- // })}
- //
-
-
- {formik.values.identification?.slice(0, 4)}
-
-
- {showId ?formik.values.identification?.slice(4):"****"}
-
-
- {showId ? : }
-
-
- }
-
+
+ {formik.values.identification?.slice(0, 4)}
+
diff --git a/src/routes/GLDUserRoutes.js b/src/routes/GLDUserRoutes.js
index a4a059c..3f893ef 100644
--- a/src/routes/GLDUserRoutes.js
+++ b/src/routes/GLDUserRoutes.js
@@ -30,6 +30,8 @@ const EmailTemplateDetailPage = Loadable(lazy(() => import('pages/EmailTemplate/
const HolidayPage = Loadable(lazy(() => import('pages/Holiday')));
const GazetteIssuePage = Loadable(lazy(() => import('pages/GazetteIssue/index')));
const DrImport = Loadable(lazy(() => import('pages/Setting/DrImport')));
+const HkidKeyMigration = Loadable(lazy(() => import('pages/Setting/HkidKeyMigration')));
+const UserPiiEncryption = Loadable(lazy(() => import('pages/Setting/UserPiiEncryption')));
const AuditLogPage = Loadable(lazy(() => import('pages/AuditLog/index')));
const ReconReportPage = Loadable(lazy(() => import('pages/Recon')));
const ChangePasswordPage = Loadable(lazy(() => import('pages/User/ChangePasswordPage')));
@@ -190,6 +192,18 @@ const GLDUserRoutes = {
element:
}:{},
+ isGranted("MAINTAIN_SETTING")?
+ {
+ path: '/setting/hkidKeyMigration',
+ element:
+ }:{},
+
+ isGranted("MAINTAIN_SETTING")?
+ {
+ path: '/setting/userPiiEncryption',
+ element:
+ }:{},
+
isGranted("MAINTAIN_SETTING")?
{
path: '/setting/auditLog',
diff --git a/src/translations/en.json b/src/translations/en.json
index a873714..2173830 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -421,7 +421,7 @@
"payTotal": "Total Payment Amount",
"payDetail": "Payment Details",
"payMethod": "Payment methods",
- "epayMethod": " e-Payment Method",
+ "epayMethod": " Payment Method",
"selectPaymentMethod": "Please select a payment method",
"selectPaymentMethodBtn": "Select payment method",
"payReceipt": "Payment Receipt",
@@ -448,7 +448,7 @@
"paymentLimitPrice2":" is only applicable when minimum amount is HK$0.10 and maximum amount is HK$9,999,999.99",
"paymentLimitPPS":" Payment could not be made via mobile device browsers, please use desktop computers to make payment.",
"paymentMethod": "Payment Method",
- "paymentProcessLimited":"Payment process must be completed within 30 minutes and return to this system.",
+ "paymentProcessLimited":"Please complete the payment process within 15 minutes. Note: For FPS payments, scanning, payment and all necessary approvals must be finished within 3 minutes due to security-related QR code expiry.",
"publicNoticeDetailTitle": "Public Notice Application Information",
"applyPerson": "Applicant",
diff --git a/src/translations/zh-CN.json b/src/translations/zh-CN.json
index 163fd83..a8aea4b 100644
--- a/src/translations/zh-CN.json
+++ b/src/translations/zh-CN.json
@@ -454,7 +454,7 @@
"payTotal": "付款总额",
"payDetail": "付款详情",
"payMethod": "付款方式",
- "epayMethod": "电子付款方法",
+ "epayMethod": "付款方法",
"selectPaymentMethod": "请选择付款方法",
"selectPaymentMethodBtn": "选择付款方法",
"payReceipt": "付款收据",
@@ -482,7 +482,7 @@
"paymentLimitPrice2":"只适用于最小金额为 0.10 港元及最高金额为 9,999,999.99港元",
"paymentLimitPPS":"付款不适用于流动装置的浏览器,请使用桌面电脑。",
"paymentMethod": "付款方式",
- "paymentProcessLimited":"付款过程必须在 30 分钟内完成及返回本系统。",
+ "paymentProcessLimited":"请于15分钟内完成付款程序。 注意:使用转数快(FPS)时,因二维码具安全时效限制,须于3分钟内完成扫码、付款及所有相关审核程序。",
"publicNoticeDetailTitle": "公共启事申请资料",
"applyPerson": "申请人",
diff --git a/src/translations/zh-HK.json b/src/translations/zh-HK.json
index c8cbe54..9124f64 100644
--- a/src/translations/zh-HK.json
+++ b/src/translations/zh-HK.json
@@ -455,7 +455,7 @@
"payTotal": "付款總額",
"payDetail": "付款詳情",
"payMethod": "付款方式",
- "epayMethod": "電子付款方法",
+ "epayMethod": "付款方法",
"selectPaymentMethod": "請選擇付款方法",
"selectPaymentMethodBtn": "選擇付款方法",
"payReceipt": "付款收據",
@@ -483,7 +483,7 @@
"paymentLimitPrice2":"只適用於最小金額為 0.10 港元及最高金額為 9,999,999.99港元",
"paymentLimitPPS":"付款不適用於流動裝置的瀏覽器,請使用桌面電腦。",
"paymentMethod": "付款方法",
- "paymentProcessLimited":"付款程序必須在 30 分鐘內完成及返回本系统。",
+ "paymentProcessLimited":"請於15分鐘內完成付款程序。 注意:使用轉數快(FPS)時,因二維碼具安全時效限制,須於3分鐘內完成掃碼、付款及所有相關審核程序。",
"publicNoticeDetailTitle": "公共啟事申請資料",
"applyPerson": "申請人",
diff --git a/src/utils/ApiPathConst.js b/src/utils/ApiPathConst.js
index 38daac3..161dff9 100644
--- a/src/utils/ApiPathConst.js
+++ b/src/utils/ApiPathConst.js
@@ -84,6 +84,9 @@ export const GET_FILE_DELETE = apiPath+'/file/delete';
export const DR_EXPORT = apiPath+'/settings/dr/export';
export const DR_IMPORT = apiPath+'/settings/dr/import';
export const OFFLINE_IMPORT = apiPath+'/settings/dr/importOffline';
+export const HKID_REKEY_MIGRATION = apiPath+'/settings/migration/hkid-rekey';
+export const USER_PII_ENCRYPT_MIGRATION = apiPath+'/settings/migration/user-pii-encrypt';
+export const USER_PII_VERIFY_MIGRATION = apiPath+'/settings/migration/user-pii-verify';
export const AUDIT_LOG_EXPORT = apiPath+'/settings/auditLog-export';
@@ -180,6 +183,7 @@ export const PAYMENT_LOAD = apiPath+'/payment/load';//GET
export const PAYMENT_APP_LIST = apiPath+'/payment/applist';//POST
export const PAYMENT_CHECK = apiPath+'/payment/check-payment';//GET
export const PAYMENT_BIB = apiPath+'/payment/set-bib';//POST
+export const PAYMENT_MARK_AS_PAID = apiPath+'/payment/mark-as-paid';//POST
export const PAYMENT_GFMIS_LIST = apiPath+'/payment/listGFMIS';//GET
export const PAYMENT_LIMIT_SETTING_LIST = apiPath+'/settings/payment';//GET