Compare commits
No commits in common. "a83e98e3c87c3e0c862dec0fbb86605d5770453e" and "66680c0baf59f81a5a16977ab7493ad6b5c641b0" have entirely different histories.
a83e98e3c8
...
66680c0baf
@ -157,10 +157,10 @@ public class MainActivity extends AppCompatActivity implements
|
||||
}
|
||||
|
||||
private void initKey(){
|
||||
// SystemParamsOperation.getInstance().setTmsAddress("https://api-tms-uat.kbzbank.com:8443/sirius");
|
||||
SystemParamsOperation.getInstance().setTmsAddress("https://sirius-nest.utsmyanmar.com");
|
||||
// SystemParamsOperation.getInstance().setEReceiptAddress("https://api-tms-uat.kbzbank.com:8443/receipt");
|
||||
SystemParamsOperation.getInstance().setEReceiptAddress("https://receipt-nest.utsmyanmar.com");
|
||||
SystemParamsOperation.getInstance().setTmsAddress("https://api-tms-uat.kbzbank.com:8443/sirius");
|
||||
// SystemParamsOperation.getInstance().setTmsAddress("https://sirius-nest.utsmyanmar.com");
|
||||
SystemParamsOperation.getInstance().setEReceiptAddress("https://api-tms-uat.kbzbank.com:8443/receipt");
|
||||
// SystemParamsOperation.getInstance().setEReceiptAddress("http://receipt-nest.utsmyanmar.com");
|
||||
|
||||
PinPad pinPad = MyApplication.getInstance().deviceEngine.getPinPad();
|
||||
byte[] encryptedPIK = SystemParamsOperation.getInstance().getPIK();
|
||||
|
||||
@ -151,9 +151,6 @@ public class CardWaitingFragment extends DataBindingFragment implements DataBind
|
||||
}else if(sharedViewModel.getIsSeePhone().getValue() != null && sharedViewModel.getIsSeePhone().getValue()) {
|
||||
cardReadViewModel.setCheckCardAlertMsg("Please Tap!",false);
|
||||
setupCardReadProcess(true);
|
||||
} else if(sharedViewModel.getIsCardAppBlock().getValue() != null && sharedViewModel.getIsCardAppBlock().getValue()) {
|
||||
cardReadViewModel.setCheckCardAlertMsg("Magstripe not allowed!",false);
|
||||
setupCardReadProcess(true);
|
||||
} else {
|
||||
setupCardReadProcess(false);
|
||||
}
|
||||
|
||||
@ -249,25 +249,7 @@ public class EmvTransactionFragment extends DataBindingFragment {
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case CARD_APP_BLOCKED:
|
||||
if(cardReadViewModel.cardTypeData.getValue()!= null && cardReadViewModel.cardTypeData.getValue() == CardTypeX.IC.value) {
|
||||
isCardInserted(new CardDetectCallback() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
sharedViewModel.setIsCardAppBlock(true);
|
||||
navigateToCheckCard();
|
||||
}
|
||||
});
|
||||
} else if(cardReadViewModel.cardTypeData.getValue() != null && cardReadViewModel.cardTypeData.getValue() == CardTypeX.NFC.value) {
|
||||
isCardTaped("Please try again",new CardDetectCallback() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
sharedViewModel.setIsCardAppBlock(true);
|
||||
navigateToCheckCard();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// sharedViewModel.set_errorFragmentMsg("Interface not found!");
|
||||
// navigateToError();
|
||||
break;
|
||||
|
||||
@ -164,9 +164,6 @@ public class EmvTransactionProcessViewModel extends EmvBaseViewModel implements
|
||||
case EMV_TRY_AGAIN:
|
||||
emvResultStatus.postValue(EmvResultStatus.READ_CARD_RETRY);
|
||||
break;
|
||||
case EMV_CARD_APP_BLOCK:
|
||||
emvResultStatus.postValue(EmvResultStatus.CARD_APP_BLOCKED);
|
||||
break;
|
||||
case EMV_CONFIRM_CODE_VERIFY:
|
||||
emvResultStatus.postValue(EmvResultStatus.CONFIRM_CODE_VERIFY);
|
||||
break;
|
||||
|
||||
@ -13,109 +13,112 @@ import java.util.Objects;
|
||||
|
||||
public class InputAmountViewModel extends ViewModel {
|
||||
|
||||
private static final String TAG = InputAmountViewModel.class.getSimpleName();
|
||||
|
||||
public MutableLiveData<String> inputAmountView = new MutableLiveData<>();
|
||||
|
||||
public SingleLiveEvent<String> invalidAmountMsg = new SingleLiveEvent<>();
|
||||
|
||||
public SingleLiveEvent<String> availableAmount = new SingleLiveEvent<>();
|
||||
|
||||
private static final int MAX_INT_DIGITS = 10;
|
||||
private static final int MAX_DECIMAL_DIGITS = 2;
|
||||
|
||||
public InputAmountViewModel() {
|
||||
inputAmountView.setValue("0");
|
||||
}
|
||||
|
||||
private String formatInteger(String value) {
|
||||
if (TextUtils.isEmpty(value)) return "0";
|
||||
double amt = Double.parseDouble(value);
|
||||
DecimalFormat formatter = new DecimalFormat("#,###");
|
||||
return formatter.format(amt);
|
||||
private int countDecimalDigits(double number) {
|
||||
String numberStr = Double.toString(number);
|
||||
int decimalIndex = numberStr.indexOf('.');
|
||||
return decimalIndex >= 0 ? numberStr.length() - decimalIndex - 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public NumberKeyboard.KeyClickCallback onKeyClick() {
|
||||
return new NumberKeyboard.KeyClickCallback() {
|
||||
|
||||
@Override
|
||||
public void onNumClick(int keyNum) {
|
||||
|
||||
String current = inputAmountView.getValue();
|
||||
if (current == null) return;
|
||||
|
||||
String raw = current.replace(",", "");
|
||||
|
||||
if (raw.contains(".")) {
|
||||
|
||||
String[] parts = raw.split("\\.");
|
||||
String intPart = parts[0];
|
||||
String decimalPart = parts.length > 1 ? parts[1] : "";
|
||||
|
||||
if (decimalPart.length() >= MAX_DECIMAL_DIGITS) {
|
||||
if (inputAmountView.getValue().length() == 15) {
|
||||
return;
|
||||
}
|
||||
|
||||
raw = raw + keyNum;
|
||||
if (TextUtils.equals(inputAmountView.getValue(), "0")) {
|
||||
inputAmountView.setValue(keyNum + "");
|
||||
} else if (inputAmountView.getValue().contains(".")) {
|
||||
StringBuilder inputAmount = new StringBuilder();
|
||||
inputAmount.append(inputAmountView.getValue());
|
||||
|
||||
} else {
|
||||
int dotIndex = inputAmount.indexOf(".");
|
||||
|
||||
if (raw.length() >= MAX_INT_DIGITS) {
|
||||
if(inputAmount.substring(dotIndex).length() > 0 && inputAmount.substring(dotIndex+1).length() == 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (TextUtils.equals(raw, "0")) {
|
||||
raw = String.valueOf(keyNum);
|
||||
} else {
|
||||
raw = raw + keyNum;
|
||||
if (inputAmountView.getValue().contains(",")) {
|
||||
inputAmountView.setValue(inputAmountView.getValue().replace(",", ""));
|
||||
}
|
||||
double amt = Double.parseDouble(inputAmountView.getValue());
|
||||
if (countDecimalDigits(amt) < 2) {
|
||||
inputAmountView.setValue(inputAmountView.getValue() + keyNum);
|
||||
}
|
||||
|
||||
if (raw.contains(".")) {
|
||||
String[] parts = raw.split("\\.");
|
||||
String formattedInt = formatInteger(parts[0]);
|
||||
String decimal = parts.length > 1 ? parts[1] : "";
|
||||
inputAmountView.setValue(formattedInt + "." + decimal);
|
||||
} else {
|
||||
inputAmountView.setValue(formatInteger(raw));
|
||||
if (inputAmountView.getValue().contains(",")) {
|
||||
inputAmountView.setValue(inputAmountView.getValue().replace(",", ""));
|
||||
}
|
||||
inputAmountView.setValue(inputAmountView.getValue() + keyNum);
|
||||
double amt = Double.parseDouble(inputAmountView.getValue());
|
||||
DecimalFormat formatter = new DecimalFormat("#,###");
|
||||
inputAmountView.setValue(formatter.format(amt));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDelClick() {
|
||||
|
||||
String current = inputAmountView.getValue();
|
||||
if (current == null) return;
|
||||
|
||||
if (current.contains(".")) return;
|
||||
|
||||
if (TextUtils.equals(current, "0")) {
|
||||
if (Objects.requireNonNull(inputAmountView.getValue()).contains(".")) {
|
||||
return;
|
||||
}
|
||||
if (inputAmountView.getValue().length() == 15) {
|
||||
return;
|
||||
}
|
||||
if (TextUtils.equals(inputAmountView.getValue(), "0")) {
|
||||
inputAmountView.setValue("0.");
|
||||
} else {
|
||||
inputAmountView.setValue(current + ".");
|
||||
|
||||
inputAmountView.setValue(inputAmountView.getValue() + ".");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCleanClick() {
|
||||
if (inputAmountView.getValue() != null) {
|
||||
if (inputAmountView.getValue().contains(".")) {
|
||||
StringBuilder inputAmount = new StringBuilder();
|
||||
inputAmount.append(inputAmountView.getValue());
|
||||
inputAmount.deleteCharAt(inputAmount.length() - 1);
|
||||
inputAmountView.setValue(inputAmount.toString());
|
||||
} else if (!inputAmountView.getValue().equals("0")) {
|
||||
String currentValue = inputAmountView.getValue();
|
||||
|
||||
String current = inputAmountView.getValue();
|
||||
if (current == null) return;
|
||||
String rawNumber = currentValue.replace(",", "");
|
||||
|
||||
String raw = current.replace(",", "");
|
||||
if (rawNumber.length() > 1) {
|
||||
rawNumber = rawNumber.substring(0, rawNumber.length() - 1);
|
||||
|
||||
if (raw.length() <= 1) {
|
||||
inputAmountView.setValue("0");
|
||||
return;
|
||||
}
|
||||
|
||||
raw = raw.substring(0, raw.length() - 1);
|
||||
|
||||
if (raw.contains(".")) {
|
||||
String[] parts = raw.split("\\.");
|
||||
String formattedInt = formatInteger(parts[0]);
|
||||
String decimal = parts.length > 1 ? parts[1] : "";
|
||||
inputAmountView.setValue(formattedInt + "." + decimal);
|
||||
double amt = Double.parseDouble(rawNumber);
|
||||
DecimalFormat formatter = new DecimalFormat("#,###");
|
||||
inputAmountView.setValue(formatter.format(amt));
|
||||
} else {
|
||||
inputAmountView.setValue(formatInteger(raw));
|
||||
inputAmountView.setValue("0");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -164,7 +164,6 @@ public class SharedViewModel extends ViewModel {
|
||||
|
||||
private SingleLiveEvent<Boolean> isFallback = new SingleLiveEvent<>();
|
||||
private SingleLiveEvent<Boolean> isSeePhone = new SingleLiveEvent<>();
|
||||
private SingleLiveEvent<Boolean> isCardAppBlock = new SingleLiveEvent<>();
|
||||
|
||||
private SingleLiveEvent<Boolean> _isCardDataExist = new SingleLiveEvent<>();
|
||||
|
||||
@ -234,10 +233,6 @@ public class SharedViewModel extends ViewModel {
|
||||
|
||||
public SingleLiveEvent<Boolean> getIsFallback() { return isFallback;}
|
||||
|
||||
public void setIsCardAppBlock(boolean status) { isCardAppBlock.setValue(status);}
|
||||
|
||||
public SingleLiveEvent<Boolean> getIsCardAppBlock() {return isCardAppBlock;}
|
||||
|
||||
public void setIsSeePhone(boolean status) { isSeePhone.setValue(status);}
|
||||
|
||||
public SingleLiveEvent<Boolean> getIsSeePhone() { return isSeePhone;}
|
||||
|
||||
@ -22,13 +22,11 @@ public final class TerminalKeyUtil {
|
||||
|
||||
public static final String TAG = TerminalKeyUtil.class.getSimpleName();
|
||||
|
||||
private static final byte[] main_key_data = ByteUtil.hexStr2Bytes("875f63741753d18811a3449090d1777b".toUpperCase()); // KBZ UAT
|
||||
// private static final byte[] main_key_data = ByteUtil.hexStr2Bytes("e121249099a677e8b7d4f6a9d49fe8d1".toUpperCase()); // MPU
|
||||
// private static final byte[] main_key_data = ByteUtil.hexStr2Bytes("875f63741753d18811a3449090d1777b".toUpperCase()); // KBZ UAT
|
||||
private static final byte[] main_key_data = ByteUtil.hexStr2Bytes("e121249099a677e8b7d4f6a9d49fe8d1".toUpperCase()); // MPU
|
||||
private static final byte[] work_key_data = new byte[16];
|
||||
|
||||
|
||||
|
||||
|
||||
public static void initNexKey() {
|
||||
byte[] IPEKByte = ByteUtil.hexStr2Bytes("5A4CFF6DE93F0488926166F3317EFD2F"); // IPEK
|
||||
byte[] IPEKKCVByte = ByteUtil.hexStr2Bytes("1F0C18");
|
||||
|
||||
@ -287,8 +287,8 @@ public class NetworkModule {
|
||||
tmsAddress = getTMSUrlFromNative();
|
||||
}
|
||||
|
||||
String baseUrl = tmsAddress.trim() + "/api/v1/"; //for on prim
|
||||
// String baseUrl = tmsAddress.trim() + "/"; //for uat and prod
|
||||
// String baseUrl = tmsAddress.trim() + "/api/v1/"; //for on prim
|
||||
String baseUrl = tmsAddress.trim() + "/"; //for uat and prod
|
||||
|
||||
final Gson gson =
|
||||
new GsonBuilder().create();
|
||||
|
||||
@ -30,6 +30,5 @@ public enum EmvResultStatus {
|
||||
CONFIRM_CODE_VERIFY,
|
||||
MPU_CARD,
|
||||
SEE_PHONE,
|
||||
OTHER_INTERFACE,
|
||||
CARD_APP_BLOCKED
|
||||
OTHER_INTERFACE
|
||||
}
|
||||
|
||||
@ -153,8 +153,6 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
|
||||
protected static final int EMV_ONLINE_PROCESS = 11;
|
||||
protected static final int EMV_ERROR = 12;
|
||||
protected static final int EMV_TRY_AGAIN = 13;
|
||||
|
||||
protected static final int EMV_CARD_APP_BLOCK = 23;
|
||||
protected static final int EMV_CTLS_TRY_AGAIN = 13;
|
||||
|
||||
protected static final int EMV_CONFIRM_CODE_VERIFY = 14;
|
||||
@ -601,7 +599,7 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
|
||||
// customPinPadKeyboard.setKeyBoard(ByteUtil.bytes2HexStr(number));
|
||||
|
||||
LogUtil.d(TAG, "PinPad: " + ByteUtil.bytes2HexStr(number));
|
||||
int[] supperLen = new int[]{0x00, 0x04, 0x06, 0x0c};
|
||||
int[] supperLen = new int[]{0x00, 0x04, 0x06};
|
||||
|
||||
|
||||
pinPad.setPinKeyboardViewMode(PinKeyboardViewModeEnum.DEFAULT);
|
||||
@ -677,8 +675,8 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
|
||||
} else {
|
||||
//contact terminal capability ; if different card brand(depend on aid) have different terminal capability
|
||||
if (ByteUtils.byteArray2HexString(aid).toUpperCase().contains("A000000004")) {
|
||||
emvHandler.setTlv(new byte[]{(byte) 0x9F, (byte) 0x33}, ByteUtil.hexStr2Bytes(terminalCapability));
|
||||
emvHandler.setTlv(new byte[]{(byte) 0xE0, (byte) 0x1D}, ByteUtils.hexString2ByteArray("6C00800000000000"));//terminal risk
|
||||
emvHandler.setTlv(new byte[]{(byte) 0x9F, (byte) 0x33}, new byte[]{(byte) 0xE0, (byte) 0xF0, (byte) 0xC8});
|
||||
emvHandler.setTlv(new byte[]{(byte) 0x9F, (byte) 0x1D}, ByteUtils.hexString2ByteArray("6C00800000000000"));//terminal risk
|
||||
|
||||
}
|
||||
}
|
||||
@ -828,11 +826,6 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
|
||||
//union pay online contactless--application should go online
|
||||
break;
|
||||
|
||||
case SdkResult.Emv_App_Block:
|
||||
case SdkResult.Emv_Card_Block:
|
||||
mHandler.sendEmptyMessage(EMV_CARD_APP_BLOCK);
|
||||
break;
|
||||
|
||||
case SdkResult.Emv_Candidatelist_Empty:// Application have no aid list
|
||||
case SdkResult.Emv_FallBack:// FallBack ,chip card reset failed
|
||||
//fallback process
|
||||
@ -1239,7 +1232,8 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
|
||||
emvHandler.setTlv(new byte[]{(byte) 0x9F, (byte) 0x1d}, ByteUtils.hexString2ByteArray("4C00800000000000"));
|
||||
} else {
|
||||
//set 9F1D terminal risk management - MasterCard. it should be same with the MTIP configuration for 9F1D
|
||||
emvHandler.setTlv(new byte[]{(byte) 0x9F, (byte) 0x1d}, ByteUtils.hexString2ByteArray("6C00800000000000"));
|
||||
// emvHandler.setTlv(new byte[]{(byte) 0x9F, (byte) 0x1d}, ByteUtils.hexString2ByteArray("6C00800000000000"));
|
||||
emvHandler.setTlv(new byte[]{(byte) 0x9F, (byte) 0x1d}, ByteUtils.hexString2ByteArray("6C7A800000000000"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -10,8 +10,8 @@
|
||||
"targetPercent": "99",
|
||||
"maxTargetPercent": "99",
|
||||
"threshold": "00000040",
|
||||
"tacDefault": "D84000A800",
|
||||
"tacOnline": "DC4004F800",
|
||||
"tacDefault": "F45084800C",
|
||||
"tacOnline": "F45084800C",
|
||||
"tacDenial": "0000000000",
|
||||
"floorLimit": "000000000000",
|
||||
"cvmLimit": 75000,
|
||||
@ -35,8 +35,8 @@
|
||||
"targetPercent": "99",
|
||||
"maxTargetPercent": "99",
|
||||
"threshold": "00000040",
|
||||
"tacDefault": "D84000A800",
|
||||
"tacOnline": "DC4004F800",
|
||||
"tacDefault": "F45084800C",
|
||||
"tacOnline": "F45084800C",
|
||||
"tacDenial": "0000000000",
|
||||
"floorLimit": "000000000000",
|
||||
"cvmLimit": 75000,
|
||||
@ -49,6 +49,7 @@
|
||||
"cateCode": "2701",
|
||||
"currencyCode": "0104"
|
||||
},
|
||||
|
||||
{
|
||||
"aidEnable": true,
|
||||
"aid": "A0000000041010C123456789",
|
||||
@ -60,8 +61,8 @@
|
||||
"targetPercent": "99",
|
||||
"maxTargetPercent": "99",
|
||||
"threshold": "00000040",
|
||||
"tacDefault": "D84000A800",
|
||||
"tacOnline": "DC4004F800",
|
||||
"tacDefault": "F45084800C",
|
||||
"tacOnline": "F45084800C",
|
||||
"tacDenial": "0000000000",
|
||||
"floorLimit": "000000000000",
|
||||
"cvmLimit": 75000,
|
||||
@ -73,5 +74,30 @@
|
||||
"ttq": "36804000",
|
||||
"cateCode": "2701",
|
||||
"currencyCode": "0104"
|
||||
},
|
||||
{
|
||||
"aidEnable": true,
|
||||
"aid": "A00000000430",
|
||||
"cardLabel": "MASTERCARD",
|
||||
"applicationVersion": "0002",
|
||||
"emvDDOL": "9F3704",
|
||||
"emvTDOL": "9F3704",
|
||||
"partialAidSelection": false,
|
||||
"targetPercent": "99",
|
||||
"maxTargetPercent": "99",
|
||||
"threshold": "00000040",
|
||||
"tacDefault": "F45084800C",
|
||||
"tacOnline": "F45084800C",
|
||||
"tacDenial": "0000000000",
|
||||
"floorLimit": "000000000000",
|
||||
"cvmLimit": 75000,
|
||||
"transLimit": "999999999999",
|
||||
"transLimitCDV": "999999999999",
|
||||
"terminalCapability": "E0F8C8",
|
||||
"riskManageData": "6C7A800000000000",
|
||||
"kernelType": "02",
|
||||
"ttq": "36804000",
|
||||
"cateCode": "2701",
|
||||
"currencyCode": "0104"
|
||||
}
|
||||
]
|
||||
@ -42,10 +42,10 @@ public class SystemParamsSettings implements Serializable {
|
||||
|
||||
// private String tmsAddress = "https://tms.smile-mm.com";
|
||||
// private String tmsAddress = "http://128.199.170.203";
|
||||
private String tmsAddress = "https://sirius-nest.utsmyanmar.com";
|
||||
// private String tmsAddress = "https://api-tms-uat.kbzbank.com:8443/sirius"; //for uat
|
||||
private String ereceiptAddress = "https://receipt-nest.utsmyanmar.com"; //for on prime
|
||||
// private String ereceiptAddress = "https://api-tms-uat.kbzbank.com:8443/receipt"; //for uat
|
||||
// private String tmsAddress = "https://sirius-nest.utsmyanmar.com";
|
||||
private String tmsAddress = "https://api-tms-uat.kbzbank.com:8443/sirius"; //for uat
|
||||
// private String ereceiptAddress = "https://receipt-nest.utsmyanmar.com"; //for on prime
|
||||
private String ereceiptAddress = "https://api-tms-uat.kbzbank.com:8443/receipt"; //for uat
|
||||
|
||||
private String binValues = "";
|
||||
|
||||
|
||||
@ -103,8 +103,8 @@ public class FieldConfig {
|
||||
/* FLD 49 */ {0, SDK_8583_LEN_BCD, 3, SDK_8583_DATA_ASC, SDK_8583_ALIGN_R, ' '},
|
||||
/* FLD 50 */ {0, SDK_8583_LEN_BCD, 12, SDK_8583_DATA_BCD, SDK_8583_ALIGN_R, '0'},
|
||||
/* FLD 51 */ {0, SDK_8583_LEN_BCD, 12, SDK_8583_DATA_BCD, SDK_8583_ALIGN_R, '0'},
|
||||
/* FLD 52 */ {2, SDK_8583_LEN_ASC, 8, SDK_8583_DATA_BIT, SDK_8583_ALIGN_L, '0'},
|
||||
// /* FLD 52 */ {0, SDK_8583_LEN_BCD, 8, SDK_8583_DATA_ASC, SDK_8583_ALIGN_L, 0},
|
||||
/* FLD 52 */ {0, SDK_8583_LEN_BCD, 8, SDK_8583_DATA_BIT, SDK_8583_ALIGN_L, 0},
|
||||
// /* FLD 52 */ {0, SDK_8583_LEN_BCD, 8, SDK_8583_DATA_ASC, SDK_8583_ALIGN_L, ' '},
|
||||
/* FLD 53 */ {2, SDK_8583_LEN_ASC, 32, SDK_8583_DATA_BCD, SDK_8583_ALIGN_L, '0'},
|
||||
/* FLD 54 */ {3, SDK_8583_LEN_BCD, 40, SDK_8583_DATA_ASC, SDK_8583_ALIGN_L, ' '},
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user