Merge pull request 'mazdak/UI-transcation-form' (#66) from mazdak/UI-transcation-form into FMFI-PRE-PRODUCTION-2026

Reviewed-on: https://ct.mfsys.com.pk/aConnect/aConnect-UX/pulls/66
FMFI-PRE-PRODUCTION-2026
Naeem Ullah 1 month ago
commit 2d4b917cea

@ -1,6 +1,30 @@
<div class="page-content"> <div id="layout-wrapper">
<div class="inner-pg-sp">
<div class="container-fluid"> <div class="container-fluid">
<!-- User Selection Card -->
<div class="row">
<div class="col-12">
<div class="d-sm-flex align-items-center justify-content-between navbar-header p-0"></div>
</div>
</div>
<div class="container-fluid">
<div class="col-xl-12 mt-4">
<!-- CARD 1: User Selection + Permissions Table -->
<div class="card border mb-4">
<div class="card-body">
<div class="table-section">
<div class="row">
<div class="col-lg-12">
<div class="card-body mt-2 p-0">
<div class="card mb-0 mt-2">
<div class="card-header font-edit-13-child mb-3">
{{ "userPermission" | translate }}
</div>
<div class="card-body">
<!-- User Selection -->
<div class="card shadow-sm mb-4"> <div class="card shadow-sm mb-4">
<div class="card-body"> <div class="card-body">
<form [formGroup]="permission" class="row align-items-center"> <form [formGroup]="permission" class="row align-items-center">
@ -8,19 +32,17 @@
{{ "userCode" | translate }} {{ "userCode" | translate }}
</label> </label>
<div class="col-md-6"> <div class="col-md-6">
<ng-select class="form-select" formControlName="userCode" [items]="users" bindLabel="userName" <ng-select class="form-select" formControlName="userCode" [items]="users"
bindValue="userId" placeholder="{{ 'choose' | translate }}" (change)="onUserChange()" bindLabel="userName" bindValue="userId"
[searchable]="true" [clearable]="false" [dropdownPosition]="'auto'" [virtualScroll]="true" placeholder="{{ 'choose' | translate }}" (change)="onUserChange()"
[bufferAmount]="20" appendTo="body"> [searchable]="true" [clearable]="false" [dropdownPosition]="'auto'"
<!-- Custom template for dropdown options --> [virtualScroll]="true" [bufferAmount]="20" appendTo="body">
<ng-template ng-option-tmp let-item="item"> <ng-template ng-option-tmp let-item="item">
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<span class="fw-medium">{{ item.userName }}</span> <span class="fw-medium">{{ item.userName }}</span>
<small class="text-muted">{{ item.userId }}</small> <small class="text-muted">{{ item.userId }}</small>
</div> </div>
</ng-template> </ng-template>
<!-- Optional: Custom template for selected item -->
<ng-template ng-label-tmp let-item="item"> <ng-template ng-label-tmp let-item="item">
<span>{{ item.userName }} ({{ item.userId }})</span> <span>{{ item.userName }} ({{ item.userId }})</span>
</ng-template> </ng-template>
@ -30,10 +52,10 @@
</div> </div>
</div> </div>
<!-- Permissions Table -->
<div class="card shadow-sm" *ngIf="showPermissions"> <div class="card shadow-sm" *ngIf="showPermissions">
<div class="card-body"> <div class="card-body">
<h4 class="card-title mb-3">{{ "menu" | translate }}</h4> <h4 class="card-title mb-3">{{ "menu" | translate }}</h4>
<div class="table-responsive scrollable-table"> <div class="table-responsive scrollable-table">
<table class="table table-hover table-bordered table-sm permission-table"> <table class="table table-hover table-bordered table-sm permission-table">
<thead class="table-light"> <thead class="table-light">
@ -43,20 +65,17 @@
<th style="width: 100px;" class="text-center">{{ "allow" | translate }}</th> <th style="width: 100px;" class="text-center">{{ "allow" | translate }}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let item of menuItems; let i = index"> <tr *ngFor="let item of menuItems; let i = index">
<td class="text-muted">{{ i + 1 }}</td> <td class="text-muted">{{ i + 1 }}</td>
<td>{{ item.endpoint | translate }}</td> <td>{{ item.endpoint | translate }}</td>
<td class="text-center"><input type="checkbox" <td class="text-center">
[(ngModel)]="item.checked" /></td> <input type="checkbox" [(ngModel)]="item.checked" />
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<div class="text-end mt-3"> <div class="text-end mt-3">
<button class="btn btn-primary btn-sm px-4" (click)="savePermissions()"> <button class="btn btn-primary btn-sm px-4" (click)="savePermissions()">
{{ "save" | translate }} {{ "save" | translate }}
@ -64,4 +83,217 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- CARD 2: Create Third Party User Form -->
<div class="card border">
<div class="card-body">
<div class="table-section">
<div class="row">
<div class="col-lg-12">
<div class="card-body mt-2 p-0">
<div class="card mb-0 mt-2">
<div class="card-header font-edit-13-child mb-3">
{{ "createThirdPartyUser" | translate }}
</div>
<div class="card-body">
<form [formGroup]="thirdPartyForm" autocomplete="off">
<div class="row g-3 mb-3">
<!-- SUS_USERCODE -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-2">
<label for="SUS_USERCODE" class="text-nowrap">
{{ "SUS_USERCODE" | translate }}<span class="mandatory">*</span>
</label>
<div class="position-relative w-100">
<input type="text" id="SUS_USERCODE" class="form-control"
formControlName="SUS_USERCODE"
placeholder="{{ 'SUS_USERCODE' | translate }}"
/>
<div class="text-danger"
*ngIf="thirdPartyForm.get('SUS_USERCODE')?.touched && thirdPartyForm.get('SUS_USERCODE')?.invalid">
<div *ngIf="thirdPartyForm.get('SUS_USERCODE')?.errors?.['required']">
{{ "fieldRequired" | translate }}
</div>
</div>
</div>
</div>
</div>
<!-- SUS_EMPCODE -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-2">
<label for="SUS_EMPCODE" class="text-nowrap">
{{ "SUS_EMPCODE" | translate }}<span class="mandatory">*</span>
</label>
<div class="position-relative w-100">
<input type="text" id="SUS_EMPCODE" class="form-control"
formControlName="SUS_EMPCODE"
placeholder="{{ 'SUS_EMPCODE' | translate }}"
appNoWhitespaces />
<div class="text-danger"
*ngIf="thirdPartyForm.get('SUS_EMPCODE')?.touched && thirdPartyForm.get('SUS_EMPCODE')?.invalid">
<div *ngIf="thirdPartyForm.get('SUS_EMPCODE')?.errors?.['required']">
{{ "fieldRequired" | translate }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<!-- SUS_NAME -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-2">
<label for="SUS_NAME" class="text-nowrap">
{{ "SUS_NAME" | translate }}<span class="mandatory">*</span>
</label>
<div class="position-relative w-100">
<input type="text" id="SUS_NAME" class="form-control"
formControlName="SUS_NAME"
placeholder="{{ 'SUS_NAME' | translate }}"
appNoWhitespaces />
<div class="text-danger"
*ngIf="thirdPartyForm.get('SUS_NAME')?.touched && thirdPartyForm.get('SUS_NAME')?.invalid">
<div *ngIf="thirdPartyForm.get('SUS_NAME')?.errors?.['required']">
{{ "fieldRequired" | translate }}
</div>
</div>
</div>
</div>
</div>
<!-- SUS_PASSWORD -->
<div class="col-md-6">
<div class="d-flex align-items-start gap-2">
<label for="SUS_PASSWORD" class="text-nowrap">
{{ "SUS_PASSWORD" | translate }}<span class="mandatory">*</span>
</label>
<div class="w-100">
<div class="password-wrapper">
<input [type]="passwordType" id="SUS_PASSWORD" class="form-control" formControlName="SUS_PASSWORD"
placeholder="{{ 'SUS_PASSWORD' | translate }}" appNoWhitespaces />
<app-password-hide-show #passShowMenu class="password-eye align-items" [showPassword]="true"
(onEyeClick)="toggleSetupPass()"></app-password-hide-show>
</div>
<div class="text-danger"
*ngIf="thirdPartyForm.get('SUS_PASSWORD')?.touched && thirdPartyForm.get('SUS_PASSWORD')?.invalid">
<div *ngIf="thirdPartyForm.get('SUS_PASSWORD')?.errors?.['required']">
{{ "fieldRequired" | translate }}
</div>
<div *ngIf="thirdPartyForm.get('SUS_PASSWORD')?.errors?.['pattern']">
{{ "passwordPattern" | translate }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<!-- SUS_EMAIL -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-2">
<label for="SUS_EMAIL" class="text-nowrap">
{{ "SUS_EMAIL" | translate }}<span class="mandatory">*</span>
</label>
<div class="position-relative w-100">
<input type="email" id="SUS_EMAIL" class="form-control"
formControlName="SUS_EMAIL"
placeholder="{{ 'SUS_EMAIL' | translate }}"
appNoWhitespaces />
<div class="text-danger"
*ngIf="thirdPartyForm.get('SUS_EMAIL')?.touched && thirdPartyForm.get('SUS_EMAIL')?.invalid">
<div *ngIf="thirdPartyForm.get('SUS_EMAIL')?.errors?.['required']">
{{ "fieldRequired" | translate }}
</div>
<div *ngIf="thirdPartyForm.get('SUS_EMAIL')?.errors?.['email']">
{{ "invalidEmail" | translate }}
</div>
</div>
</div>
</div>
</div>
<!-- SUS_USERCELLNO -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-2">
<label for="SUS_USERCELLNO" class="text-nowrap">
{{ "SUS_USERCELLNO" | translate }}<span class="mandatory">*</span>
</label>
<div class="position-relative w-100">
<input type="tel" id="SUS_USERCELLNO" class="form-control"
formControlName="SUS_USERCELLNO"
placeholder="{{ 'SUS_USERCELLNO' | translate }}"
(keypress)="onlyNumbers($event)"
maxlength="10"
appNoWhitespaces />
<div class="text-danger"
*ngIf="thirdPartyForm.get('SUS_USERCELLNO')?.touched && thirdPartyForm.get('SUS_USERCELLNO')?.invalid">
<div *ngIf="thirdPartyForm.get('SUS_USERCELLNO')?.errors?.['required']">
{{ "fieldRequired" | translate }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<!-- SUS_ACTIVE -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-2">
<input type="checkbox" id="SUS_ACTIVE" class="form-check-input"
formControlName="SUS_ACTIVE" />
<label for="SUS_ACTIVE" class="form-check-label">
{{ "SUS_ACTIVE" | translate }}
</label>
</div>
</div>
<!-- SUS_THIRDPARTY -->
<div class="col-md-6">
<div class="d-flex align-items-center gap-2">
<input type="checkbox" id="SUS_THIRDPARTY" class="form-check-input"
formControlName="SUS_THIRDPARTY" />
<label for="SUS_THIRDPARTY" class="form-check-label">
{{ "SUS_THIRDPARTY" | translate }}
</label>
</div>
</div>
</div>
<div class="text-end mt-3">
<button class="btn btn-primary btn-sm px-4" (click)="submitForm()">
{{ "save" | translate }}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div> </div>

@ -1,5 +1,5 @@
import { Component } from '@angular/core'; import { Component, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
import { PermissionNode } from '../utils/app.interfaces'; import { PermissionNode } from '../utils/app.interfaces';
import { CredentialService } from '../services/credential.service'; import { CredentialService } from '../services/credential.service';
import { I18NService } from '../services/i18n.service'; import { I18NService } from '../services/i18n.service';
@ -10,22 +10,27 @@ import { HttpErrorResponse, HttpParams } from '@angular/common/http';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { NgSelectModule } from '@ng-select/ng-select'; import { NgSelectModule } from '@ng-select/ng-select';
import { filter, Observable, take } from 'rxjs'; import { filter, Observable, take } from 'rxjs';
import { SuccessMessages } from '../utils/enums'; import { ErrorMessages, SuccessMessages } from '../utils/enums';
import { URIService } from '../app.uri'; import { URIService } from '../app.uri';
import { PasswordHideShowComponent } from '../shared/components/password-hide-show/password-hide-show.component';
import { error } from 'console';
@Component({ @Component({
selector: 'app-menu', selector: 'app-menu',
imports: [TranslateModule, ReactiveFormsModule, CommonModule, TranslateModule, NgSelectModule, FormsModule], imports: [TranslateModule, ReactiveFormsModule, ReactiveFormsModule, CommonModule, TranslateModule, NgSelectModule, FormsModule, PasswordHideShowComponent],
templateUrl: './menu.component.html', templateUrl: './menu.component.html',
styleUrl: './menu.component.scss' styleUrl: './menu.component.scss'
}) })
export class MenuComponent { export class MenuComponent {
users: any[] = []; users: any[] = [];
thirdPartyForm!: FormGroup;
permission: FormGroup; permission: FormGroup;
showPermissions = false; showPermissions = false;
permissions: PermissionNode[] = []; permissions: PermissionNode[] = [];
saving = false; saving = false;
passwordType: string = 'password';
menuItems: { endpoint: string; checked: boolean }[] = []; menuItems: { endpoint: string; checked: boolean }[] = [];
@ViewChild('passShowMenu') passwordHideShow?: PasswordHideShowComponent;
constructor( constructor(
private credentialService: CredentialService, private credentialService: CredentialService,
@ -38,11 +43,102 @@ export class MenuComponent {
this.defaultPermissions().subscribe((data: PermissionNode[]) => { this.defaultPermissions().subscribe((data: PermissionNode[]) => {
this.permissions = data; this.permissions = data;
}); });
} }
ngOnInit() { ngOnInit() {
this.getAllUsers(); this.getAllUsers();
this.loadTransactionEndpoints(); this.loadTransactionEndpoints();
this.createThirdPartyUserForm();
}
toggleSetupPass() {
this.passwordType = this.passwordHideShow?.showPassword ? 'password' : 'text';
}
createThirdPartyUserForm(): void{
this.thirdPartyForm = this.fb.group({
SUS_USERCODE: ["", [Validators.required]],
SUS_EMPCODE: ["", [Validators.required]],
SUS_NAME: ["", [Validators.required]],
SUS_PASSWORD: ['', [
Validators.required,
Validators.minLength(8),
Validators.maxLength(20),
Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]+$/)
]],
SUS_EMAIL: ["", [Validators.required, Validators.email]],
SUS_USERCELLNO: ["", [
Validators.required,
]],
POR_ORGACODE: [this.credentialService.getPorOrgacode()],
SUS_ACTIVE: [true],
SUS_THIRDPARTY: [true],
})
}
onlyNumbers(event: KeyboardEvent) {
const charCode = event.which ? event.which : event.keyCode;
if (charCode < 48 || charCode > 57) {
event.preventDefault();
}
}
submitForm() {
if (this.thirdPartyForm.invalid) {
this.thirdPartyForm.markAllAsTouched();
return;
}
const f = this.thirdPartyForm.value;
const payload = {
formId: "SH_SM_US_USER",
postProcessFormId: "SH_SM_US_USER",
workFlowId: null,
operation: "nonwizard",
porOrgacode: this.credentialService.getPorOrgacode(),
usercode: this.credentialService.getUserId(),
uniqueConstraints: [["SUS_USERCODE", "POR_ORGACODE"]],
formCounters: [],
susUsercode: f.SUS_USERCODE,
susName: f.SUS_NAME,
susEmpcode: f.SUS_EMPCODE,
susPassword: f.SUS_PASSWORD,
susEmail: f.SUS_EMAIL,
susUsercellno: f.SUS_USERCELLNO,
susActive: f.SUS_ACTIVE,
susThirdparty: f.SUS_THIRDPARTY,
}
console.log("payload",payload )
this.httpService.requestPOST(URIKey.CREATE_THIRD_PARTY_USER, payload)
.subscribe({
next: (response: any) => {
if (!(response instanceof HttpErrorResponse)) {
this.i18nService.success(SuccessMessages.SAVED_SUCCESSFULLY, []);
this.createThirdPartyUserForm();
this.getAllUsers();
this.permission.reset();
this.showPermissions = false;
}
},
error: (error: any) => {
const errorCode = error?.error?.errorCode || error?.errorCode;
switch (errorCode) {
case 'ERR_SEC_0002':
this.i18nService.error(ErrorMessages.USERNAME_ALREADY_EXISTS, []);
break;
case 'ERR_SEC_0001':
this.i18nService.error(ErrorMessages.EMAIL_ALREADY_EXISTS, []);
break;
default:
this.i18nService.error('Unexpected error', []);
}
}
});
} }
loadTransactionEndpoints() { loadTransactionEndpoints() {
@ -127,7 +223,9 @@ savePermissions() {
next: (response: any) => { next: (response: any) => {
if (!(response instanceof HttpErrorResponse)) { if (!(response instanceof HttpErrorResponse)) {
this.i18nService.success(SuccessMessages.SAVED_SUCCESSFULLY, []); this.i18nService.success(SuccessMessages.SAVED_SUCCESSFULLY, []);
this.onUserChange(); // this triggers one GET — expected this.permission.reset();
this.showPermissions = false;
this.menuItems.forEach(item => item.checked = false);
} }
}, },
complete: () => { complete: () => {

@ -73,7 +73,7 @@
</div> </div>
<div class="row g-3 mb-3"> <div class="row g-3 mb-3">
<div class="col-md-6"> <div class="col-md-6">
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-start gap-2">
<label for="confirmPassword" class="text-nowrap"> <label for="confirmPassword" class="text-nowrap">
{{ 'confirmPassword' | translate }}<span {{ 'confirmPassword' | translate }}<span
class="mandatory">*</span> class="mandatory">*</span>

@ -189,11 +189,12 @@
<!-- Password --> <!-- Password -->
<!-- Password field (only show in create mode) --> <!-- Password field (only show in create mode) -->
<div class="col-md-6" *ngIf="mode === 'create'"> <div class="col-md-6" *ngIf="mode === 'create'">
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-start gap-2">
<label for="defaultPassword" class="text-nowrap"> <label for="defaultPassword" class="text-nowrap">
{{ "password" | translate }}<span class="mandatory">*</span> {{ "password" | translate }}<span class="mandatory">*</span>
</label> </label>
<div class="password-wrapper position-relative w-100"> <div class="w-100">
<div class="password-wrapper">
<input <input
id="defaultPassword" id="defaultPassword"
[type]="passwordType" [type]="passwordType"
@ -209,6 +210,7 @@
[showPassword]="true" [showPassword]="true"
(onEyeClick)="toggleSetupPass()" (onEyeClick)="toggleSetupPass()"
></app-password-hide-show> ></app-password-hide-show>
</div>
<div <div
class="text-danger" class="text-danger"
*ngIf="userForm.get('defaultPassword')?.touched && userForm.get('defaultPassword')?.invalid" *ngIf="userForm.get('defaultPassword')?.touched && userForm.get('defaultPassword')?.invalid"

@ -12,6 +12,8 @@ export enum ErrorMessages{
USER_FETCH_FAILED = "USER_FETCH_FAILED", USER_FETCH_FAILED = "USER_FETCH_FAILED",
RESET_PASSWORD_FAILED = "RESET_PASSWORD_FAILED", RESET_PASSWORD_FAILED = "RESET_PASSWORD_FAILED",
CHANGE_PASSWORD_FAILED = "ERR_SEC_0007", CHANGE_PASSWORD_FAILED = "ERR_SEC_0007",
EMAIL_ALREADY_EXISTS = "ERR_SEC_0001",
USERNAME_ALREADY_EXISTS = "ERR_SEC_0002"
} }

@ -22,7 +22,8 @@ export enum URIKey {
GL_TO_ACCOUNT = "GL_TO_ACCOUNT", GL_TO_ACCOUNT = "GL_TO_ACCOUNT",
TRANSACTION_PERMISSIONS_ASSIGN = "TRANSACTION_PERMISSIONS_ASSIGN", TRANSACTION_PERMISSIONS_ASSIGN = "TRANSACTION_PERMISSIONS_ASSIGN",
TRANSACTION_PERMISSIONS = "TRANSACTION_PERMISSIONS", TRANSACTION_PERMISSIONS = "TRANSACTION_PERMISSIONS",
TRANSACTION_ENDPOINTS = "TRANSACTION_ENDPOINTS" TRANSACTION_ENDPOINTS = "TRANSACTION_ENDPOINTS",
CREATE_THIRD_PARTY_USER = "CREATE_THIRD_PARTY_USER"
} }

@ -121,6 +121,11 @@
"Id": "ENTITY_TRANSACTION_ENDPOINTS", "Id": "ENTITY_TRANSACTION_ENDPOINTS",
"URI": "/transaction-permissions/endpoints", "URI": "/transaction-permissions/endpoints",
"UUID": "TRANSACTION_ENDPOINTS" "UUID": "TRANSACTION_ENDPOINTS"
},
{
"Id": "ENTITY_CREATE_THIRD_PARTY_USER",
"URI": "/createThirdPartyUser",
"UUID": "CREATE_THIRD_PARTY_USER"
} }
] ]
} }

@ -339,5 +339,15 @@
"seventeen": "١٧", "seventeen": "١٧",
"eighteen": "١٨", "eighteen": "١٨",
"nineteen": "١٩", "nineteen": "١٩",
"twenty": "٢٠" "twenty": "٢٠",
"SUS_USERCODE": "رمز المستخدم",
"SUS_EMPCODE": "رمز الموظف",
"SUS_NAME": "الاسم الكامل",
"SUS_PASSWORD": "كلمة المرور",
"SUS_EMAIL": "البريد الإلكتروني",
"SUS_USERCELLNO": "رقم الجوال",
"SUS_ACTIVE": "الحساب نشط",
"SUS_THIRDPARTY": "طرف ثالث",
"createThirdPartyUser": "إنشاء مستخدم طرف ثالث",
"userPermission": "صلاحية المستخدم"
} }

@ -254,7 +254,7 @@
"noThirdPartyRegFound": "No Third Party Registration Details Found", "noThirdPartyRegFound": "No Third Party Registration Details Found",
"ERR_SEC_0001": "Email already exists", "ERR_SEC_0001": "Email already exists",
"ERR_SEC_0007": "New password cannot be same as old password", "ERR_SEC_0007": "New password cannot be same as old password",
"ERR_SEC_0002": "User ID already exists", "ERR_SEC_0002": "Username already exists",
"ERR_SEC_0003": "Old Password is not correct", "ERR_SEC_0003": "Old Password is not correct",
"ERR_SEC_0004": "Invalid credentials", "ERR_SEC_0004": "Invalid credentials",
"ERR_SEC_0005": "User not found", "ERR_SEC_0005": "User not found",
@ -340,5 +340,15 @@
"seventeen": "17", "seventeen": "17",
"eighteen": "18", "eighteen": "18",
"nineteen": "19", "nineteen": "19",
"twenty": "20" "twenty": "20",
"SUS_USERCODE": "User Code",
"SUS_EMPCODE": "Employee Code",
"SUS_NAME": "Full Name",
"SUS_PASSWORD": "Password",
"SUS_EMAIL": "Email",
"SUS_USERCELLNO": "Cell Number",
"SUS_ACTIVE": "Account Active",
"SUS_THIRDPARTY": "Third Party",
"createThirdPartyUser": "Create Third Party User",
"userPermission": "User Permission"
} }
Loading…
Cancel
Save