refs #5870 feat:operatorSalix
This commit is contained in:
parent
1e734703b2
commit
c9d7978519
|
@ -2478,47 +2478,16 @@ class CollectionFragmentPicker(
|
||||||
customDialogThreeButtons.setDescription(getString(R.string.txtnuevacantidad))
|
customDialogThreeButtons.setDescription(getString(R.string.txtnuevacantidad))
|
||||||
.setValue("")
|
.setValue("")
|
||||||
|
|
||||||
//Tarea4495
|
|
||||||
// if (type != SACADOR) {
|
|
||||||
/* customDialogThreeButtons.setOkButton(getString(R.string.titleFaults)) {
|
|
||||||
checkAndCall(
|
|
||||||
position,
|
|
||||||
customDialogThreeButtons.getValue(),
|
|
||||||
getString(R.string.titleFaults)
|
|
||||||
)
|
|
||||||
|
|
||||||
}.setOkButtonTwo(getString(R.string.BasuraRechazar)) {
|
|
||||||
|
|
||||||
checkAndCall(
|
|
||||||
position,
|
|
||||||
customDialogThreeButtons.getValue(),
|
|
||||||
getString(R.string.BasuraRechazar)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
// }
|
|
||||||
|
|
||||||
customDialogThreeButtons.setOkButtonThree(getString(R.string.Reject)) {
|
|
||||||
checkAndCall(
|
|
||||||
position,
|
|
||||||
customDialogThreeButtons.getValue(),
|
|
||||||
getString(R.string.Reject)
|
|
||||||
)
|
|
||||||
|
|
||||||
}.setOkButtonFour(getString(R.string.Split)) {
|
|
||||||
checkAndCall(
|
|
||||||
position,
|
|
||||||
customDialogThreeButtons.getValue(),
|
|
||||||
getString(R.string.Split)
|
|
||||||
)*/
|
|
||||||
|
|
||||||
|
|
||||||
.setOkButtonAdd(getString(R.string.Agregar)) {
|
.setOkButtonAdd(getString(R.string.Agregar)) {
|
||||||
/* checkAndCall(
|
|
||||||
position,
|
try {
|
||||||
customDialogThreeButtons.getValue(),
|
|
||||||
getString(R.string.Agregar)
|
|
||||||
)*/
|
|
||||||
increaseQuantity(position, customDialogThreeButtons.getValue().toInt())
|
increaseQuantity(position, customDialogThreeButtons.getValue().toInt())
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
getString(R.string.errorInput).toast(requireContext())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
scanRequest()
|
scanRequest()
|
||||||
customDialogThreeButtons.dismiss()
|
customDialogThreeButtons.dismiss()
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package es.verdnatura.presentation.view.feature.login.fragment
|
package es.verdnatura.presentation.view.feature.login.fragment
|
||||||
|
|
||||||
//import es.verdnatura.presentation.view.feature.login.model.LoginItemVO
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
@ -11,6 +9,7 @@ import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
|
import android.util.Log.d
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
|
@ -122,7 +121,7 @@ class LoginFragment(var imageUri: Uri?) :
|
||||||
//saveData("SERIALNUMBER", file.readText())
|
//saveData("SERIALNUMBER", file.readText())
|
||||||
mobileApplication.serialNumber = file.readText()
|
mobileApplication.serialNumber = file.readText()
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
""
|
d("VERDNATURA:",getString(R.string.errorFile))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -186,8 +185,6 @@ class LoginFragment(var imageUri: Uri?) :
|
||||||
.hideDialog()
|
.hideDialog()
|
||||||
.setOkButton(getString(R.string.cancel)) {
|
.setOkButton(getString(R.string.cancel)) {
|
||||||
customDialogList.dismiss()
|
customDialogList.dismiss()
|
||||||
// customNewForm.dismiss()
|
|
||||||
// customDialog.dismiss()
|
|
||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
|
|
||||||
|
@ -323,17 +320,17 @@ class LoginFragment(var imageUri: Uri?) :
|
||||||
.setOkButton(getString(R.string.close)) {
|
.setOkButton(getString(R.string.close)) {
|
||||||
customDialog.dismiss()
|
customDialog.dismiss()
|
||||||
binding.splashProgress.visibility = View.GONE
|
binding.splashProgress.visibility = View.GONE
|
||||||
// goToMain()
|
|
||||||
}.show()
|
}.show()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
//sergio: se añade el log
|
//sergio: se añade el log
|
||||||
viewModel.getCurrentUserData( getString(R.string.logAppName),
|
viewModel.getCurrentUserData(
|
||||||
|
getString(R.string.logAppName),
|
||||||
getInfoVersionNameApp(),
|
getInfoVersionNameApp(),
|
||||||
getData(ANDROID_ID))
|
getData(ANDROID_ID)
|
||||||
|
)
|
||||||
viewModel.worker_getSector()
|
viewModel.worker_getSector()
|
||||||
viewModel.worker_getPrinter()
|
viewModel.worker_getPrinter()
|
||||||
//viewModel.operator_getDataSalix("{\"where\": {\"workerFk\":${getDataInt(USERFK)}}}")
|
|
||||||
|
|
||||||
if (binding.switchRemember.isChecked) {
|
if (binding.switchRemember.isChecked) {
|
||||||
saveRemember(true)
|
saveRemember(true)
|
||||||
|
@ -341,19 +338,18 @@ class LoginFragment(var imageUri: Uri?) :
|
||||||
saveRemember(false)
|
saveRemember(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (it.vIsAuthorized == "1" && it.vMessage.isNullOrEmpty()) {
|
if (it.vIsAuthorized == "1") {
|
||||||
|
|
||||||
|
if (it.vMessage.isNullOrEmpty()) {
|
||||||
getVersion()
|
getVersion()
|
||||||
|
} else {
|
||||||
}
|
|
||||||
if (it.vIsAuthorized == "1" && !it.vMessage.isNullOrEmpty()) {
|
|
||||||
//binding.splashProgress.visibility = View.GONE
|
|
||||||
customDialog.setTitle(getString(R.string.info))
|
customDialog.setTitle(getString(R.string.info))
|
||||||
.setDescription(it.vMessage)
|
.setDescription(it.vMessage)
|
||||||
.setOkButton(getString(R.string.close)) {
|
.setOkButton(getString(R.string.close)) {
|
||||||
customDialog.dismiss()
|
customDialog.dismiss()
|
||||||
getVersion()
|
getVersion()
|
||||||
}.show()
|
}.show()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,6 +364,14 @@ class LoginFragment(var imageUri: Uri?) :
|
||||||
saveUserFkPref(it.Id.toString())
|
saveUserFkPref(it.Id.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//Tarea 5870
|
||||||
|
workerOperator.observe(viewLifecycleOwner) {
|
||||||
|
if (!it.isError) {
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
operatorAdd.observe(viewLifecycleOwner) {
|
operatorAdd.observe(viewLifecycleOwner) {
|
||||||
|
|
||||||
if (it.isError) {
|
if (it.isError) {
|
||||||
|
@ -427,35 +431,7 @@ class LoginFragment(var imageUri: Uri?) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* loadOperatorList.observe(viewLifecycleOwner, Observer { event ->
|
|
||||||
//binding.splashProgress.visibility = View.GONE
|
|
||||||
|
|
||||||
event.getContentIfNotHandled().notNull {
|
|
||||||
|
|
||||||
if (it.list.isEmpty()) {
|
|
||||||
"No se han podido obtener datos de Salix".toast(context)
|
|
||||||
removePrinter()
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (!it.list.get(0).isError) {
|
|
||||||
saveDataInt(NUMBEROFWAGONS, it.list[0].numberOfWagons)
|
|
||||||
saveDataInt(PRINTERFK, it.list[0].labelerFk!!)
|
|
||||||
saveDataInt(TRAINFK, it.list[0].trainFk)
|
|
||||||
saveData(ITEMPACKINGFK, it.list[0].itemPackingTypeFk)
|
|
||||||
|
|
||||||
//saveData(PRINTERNAME, it.list.get(0).name)
|
|
||||||
} else {
|
|
||||||
it.list.get(0).errorMessage.toast(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
})*/
|
|
||||||
|
|
||||||
|
|
||||||
loadWorkerPrintList.observe(viewLifecycleOwner, Observer { event ->
|
loadWorkerPrintList.observe(viewLifecycleOwner, Observer { event ->
|
||||||
//binding.splashProgress.visibility = View.GONE
|
|
||||||
|
|
||||||
event.getContentIfNotHandled().notNull {
|
event.getContentIfNotHandled().notNull {
|
||||||
|
|
||||||
|
@ -465,8 +441,8 @@ class LoginFragment(var imageUri: Uri?) :
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!it.list.get(0).isError) {
|
if (!it.list.get(0).isError) {
|
||||||
saveDataInt(PRINTERFK, it.list.get(0).id!!)
|
saveDataInt(PRINTERFK, it.list[0].id)
|
||||||
saveData(PRINTERNAME, it.list.get(0).name)
|
saveData(PRINTERNAME, it.list[0].name)
|
||||||
} else {
|
} else {
|
||||||
it.list.get(0).errorMessage.toast(context)
|
it.list.get(0).errorMessage.toast(context)
|
||||||
}
|
}
|
||||||
|
@ -476,8 +452,6 @@ class LoginFragment(var imageUri: Uri?) :
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
loginsalixitem.observe(viewLifecycleOwner) {
|
loginsalixitem.observe(viewLifecycleOwner) {
|
||||||
|
|
||||||
if (it.isError) {
|
if (it.isError) {
|
||||||
|
@ -514,7 +488,7 @@ class LoginFragment(var imageUri: Uri?) :
|
||||||
|
|
||||||
//Tarea 5613
|
//Tarea 5613
|
||||||
viewModel.getAccessTokenConfigs()
|
viewModel.getAccessTokenConfigs()
|
||||||
//viewModel.operator_add()
|
viewModel.operator_add()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -528,9 +502,7 @@ class LoginFragment(var imageUri: Uri?) :
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!it.list[0].isError) {
|
if (!it.list[0].isError) {
|
||||||
/* app.renewPeriod = it.list[0].renewPeriod!!
|
saveDataLong("renewPeriod", it.list[0].renewPeriod)
|
||||||
app.renewInterval = it.list[0].renewInterval!!*/
|
|
||||||
saveDataLong("renewPeriod", it.list[0].renewPeriod!!)
|
|
||||||
saveDataLong("renewInterval", it.list[0].renewInterval)
|
saveDataLong("renewInterval", it.list[0].renewInterval)
|
||||||
viewModel.operator_add()
|
viewModel.operator_add()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -75,6 +75,11 @@ class LoginViewModel(val context: Context) : BaseViewModel(context) {
|
||||||
|
|
||||||
private val _workerPrintList by lazy { MutableLiveData<WorkerPrintersList>() }
|
private val _workerPrintList by lazy { MutableLiveData<WorkerPrintersList>() }
|
||||||
private val _workerOperatorList by lazy { MutableLiveData<OperatorList>() }
|
private val _workerOperatorList by lazy { MutableLiveData<OperatorList>() }
|
||||||
|
|
||||||
|
private val _workerOperator by lazy { MutableLiveData<OperatorSalix>() }
|
||||||
|
val workerOperator: LiveData<OperatorSalix>
|
||||||
|
get() = _workerOperator
|
||||||
|
|
||||||
private val _accessConfigSalixList by lazy { MutableLiveData<accessConfigSalixList>() }
|
private val _accessConfigSalixList by lazy { MutableLiveData<accessConfigSalixList>() }
|
||||||
|
|
||||||
private val _renewTokenResponse by lazy { MutableLiveData<RenewToken>() }
|
private val _renewTokenResponse by lazy { MutableLiveData<RenewToken>() }
|
||||||
|
@ -180,17 +185,30 @@ class LoginViewModel(val context: Context) : BaseViewModel(context) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCurrentUserData(appName: String, versionApp: String, android_id: String, serialnumber: String? =null) {
|
fun getCurrentUserData(
|
||||||
|
appName: String,
|
||||||
|
versionApp: String,
|
||||||
|
android_id: String,
|
||||||
|
serialnumber: String? = null
|
||||||
|
) {
|
||||||
salix.getCurrentUserData().enqueue(object : SilexCallback<DataUserSalix>(context) {
|
salix.getCurrentUserData().enqueue(object : SilexCallback<DataUserSalix>(context) {
|
||||||
override fun onSuccess(response: Response<DataUserSalix>) {
|
override fun onSuccess(response: Response<DataUserSalix>) {
|
||||||
app.userName = response.body()?.let { it.nickname }
|
app.userName = response.body()?.let { it.nickname }
|
||||||
app.userId = response.body()?.let { it.id }
|
app.userId = response.body()?.let { it.id }
|
||||||
deviceLog_addSalix(app = appName, versionApp= versionApp,android_id= android_id, userFk = app.userId!!, serialnumber = serialnumber)
|
deviceLog_addSalix(
|
||||||
|
app = appName,
|
||||||
|
versionApp = versionApp,
|
||||||
|
android_id = android_id,
|
||||||
|
userFk = app.userId!!,
|
||||||
|
serialnumber = serialnumber
|
||||||
|
)
|
||||||
|
//Tarea 5870
|
||||||
|
//operator_getDataSalix(app.userId!!)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fun deviceLog_add(
|
/* fun deviceLog_add(
|
||||||
app: String, versionApp: String, android_id: String, userFk :Int
|
app: String, versionApp: String, android_id: String, userFk :Int
|
||||||
) {
|
) {
|
||||||
//Tarea 4815
|
//Tarea 4815
|
||||||
|
@ -271,68 +289,10 @@ class LoginViewModel(val context: Context) : BaseViewModel(context) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fun nodeJsTest(smarttag: String, wagon: String, shelving: String)
|
|
||||||
{
|
|
||||||
getLoginUserCase.nodeJsTest(smarttag, wagon, shelving)
|
|
||||||
.enqueue(object : Callback<NodeJsService.SmartTagNode>
|
|
||||||
{
|
|
||||||
override fun onResponse(
|
|
||||||
call: Call<NodeJsService.SmartTagNode>,
|
|
||||||
response: Response<NodeJsService.SmartTagNode>
|
|
||||||
)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
val workerId: NodeJsService.SmartTagNode?
|
|
||||||
|
|
||||||
*//* if (response.isSuccessful()){
|
|
||||||
//Log.i("VERDNATURA::","OK")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!response.errorBody().toString().isEmpty()){
|
|
||||||
|
|
||||||
}*//*
|
|
||||||
|
|
||||||
if (response.body() != null)
|
|
||||||
{
|
|
||||||
|
|
||||||
workerId = NodeJsService.SmartTagNode(
|
|
||||||
response.body().toString(),
|
|
||||||
isError = false,
|
|
||||||
errorMessage = ""
|
|
||||||
)
|
|
||||||
|
|
||||||
} else
|
|
||||||
{
|
|
||||||
workerId = NodeJsService.SmartTagNode(
|
|
||||||
isError = true,
|
|
||||||
errorMessage = "Error al llamar al servicio Node."
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
_nodejs.value = workerId
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(call: Call<NodeJsService.SmartTagNode>, t: Throwable)
|
|
||||||
{
|
|
||||||
val workerId =
|
|
||||||
NodeJsService.SmartTagNode(isError = true, errorMessage = t.message!!)
|
|
||||||
|
|
||||||
//Log.i("VERDNATURA::","el error nodejs es "+t.message+"--"+t.cause.toString()+"--"+t.stackTrace.toString())
|
|
||||||
|
|
||||||
_nodejs.value = workerId
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
}*/
|
|
||||||
|
|
||||||
fun getListFromJSON(json: JsonObject): MutableList<itemsExpeditionDynamics> {
|
fun getListFromJSON(json: JsonObject): MutableList<itemsExpeditionDynamics> {
|
||||||
val gson = Gson()
|
val gson = Gson()
|
||||||
var list = mutableListOf<itemsExpeditionDynamics>()
|
val list = mutableListOf<itemsExpeditionDynamics>()
|
||||||
|
val expeditionState: Map<String, Any> =
|
||||||
// val mapType = object : TypeToken<Map<String, Any>>() {}.type
|
|
||||||
|
|
||||||
var expeditionState: Map<String, Any> =
|
|
||||||
gson.fromJson(json, object : TypeToken<Map<String, Any>>() {}.type)
|
gson.fromJson(json, object : TypeToken<Map<String, Any>>() {}.type)
|
||||||
expeditionState.forEach {
|
expeditionState.forEach {
|
||||||
|
|
||||||
|
@ -460,36 +420,32 @@ class LoginViewModel(val context: Context) : BaseViewModel(context) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun operator_getDataSalix(
|
|
||||||
workerId: String
|
|
||||||
) {
|
|
||||||
|
|
||||||
salix.operator_getData(workerId)
|
//Tarea 5870
|
||||||
.enqueue(object : SilexCallback<List<OperatorSalix>>(context) {
|
fun operator_getDataSalix(
|
||||||
|
workerId: Int
|
||||||
|
) {
|
||||||
|
val filter =
|
||||||
|
"""{"fields":["itemPackingTypeFk","numberOfWagons","sectorFk","trainFk","labelerFk"],"include":[{"relation":"sector","scope":{"fields":["description","warehouseFk"]}}]}"""
|
||||||
|
salix.operator_getData(id = workerId, filter)
|
||||||
|
.enqueue(object : SilexCallback<OperatorSalix>(context) {
|
||||||
override fun onError(t: Throwable) {
|
override fun onError(t: Throwable) {
|
||||||
val listError: ArrayList<OperatorSalix> = ArrayList()
|
|
||||||
listError.add(
|
_workerOperator.value = OperatorSalix(
|
||||||
OperatorSalix(
|
|
||||||
isError = true,
|
isError = true,
|
||||||
errorMessage = getMessageFromAllResponse(
|
errorMessage = getMessageFromAllResponse(
|
||||||
nameofFunction(this),
|
nameofFunction(this),
|
||||||
t.message!!
|
t.message!!
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
_workerOperatorList.value = OperatorList(listError)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSuccess(response: Response<List<OperatorSalix>>) {
|
override fun onSuccess(response: Response<OperatorSalix>) {
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
_workerOperatorList.value = response.body()?.let {
|
_workerOperator.value = response.body()
|
||||||
OperatorList(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
val listError: ArrayList<OperatorSalix> = ArrayList()
|
_workerOperator.value = response.body()?.let {
|
||||||
listError.add(
|
|
||||||
OperatorSalix(
|
OperatorSalix(
|
||||||
isError = true,
|
isError = true,
|
||||||
errorMessage = getMessageFromAllResponse(
|
errorMessage = getMessageFromAllResponse(
|
||||||
|
@ -497,9 +453,7 @@ class LoginViewModel(val context: Context) : BaseViewModel(context) {
|
||||||
response.message()
|
response.message()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
_workerOperatorList.value = OperatorList(listError)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -560,7 +514,7 @@ class LoginViewModel(val context: Context) : BaseViewModel(context) {
|
||||||
|
|
||||||
override fun onSuccess(response: Response<RenewToken>) {
|
override fun onSuccess(response: Response<RenewToken>) {
|
||||||
|
|
||||||
var RenewToken = response.body()
|
val RenewToken = response.body()
|
||||||
val prefs = app.getPrefsEditor()
|
val prefs = app.getPrefsEditor()
|
||||||
prefs.putString("token", RenewToken!!.id)
|
prefs.putString("token", RenewToken!!.id)
|
||||||
prefs.putLong("ttl", RenewToken!!.ttl)
|
prefs.putLong("ttl", RenewToken!!.ttl)
|
||||||
|
|
|
@ -38,18 +38,20 @@ class SalixGrupo(
|
||||||
val message: String = ""
|
val message: String = ""
|
||||||
|
|
||||||
)
|
)
|
||||||
|
//Tarea 5870
|
||||||
class OperatorSalix(
|
class OperatorSalix(
|
||||||
val workerFk: Int = 0,
|
val sector: Sector? = null,
|
||||||
val sectorFk: Int = 0,
|
val train: Train? = null,
|
||||||
val labelerFk: Int = 0,
|
val labeller: Printer? = null,
|
||||||
val numberOfWagons: Int = 0,
|
val numberOfWagons: Int = 0,
|
||||||
val trainFk: Int = 0,
|
var itemPackingTypeFk: String? = null,
|
||||||
val warehouseFk: Int = 0,
|
|
||||||
var itemPackingTypeFk: String = "",
|
|
||||||
val isError: Boolean = false,
|
val isError: Boolean = false,
|
||||||
var errorMessage: String = ""
|
var errorMessage: String = ""
|
||||||
)
|
)
|
||||||
|
data class Sector (val id:Int, val description:String,val warehouseFk:Int)
|
||||||
|
data class Printer(val id:Int, val name:String)
|
||||||
|
data class Train(val name:String)
|
||||||
|
|
||||||
|
|
||||||
class accessConfigSalix(
|
class accessConfigSalix(
|
||||||
val id: Number = 0,
|
val id: Number = 0,
|
||||||
|
|
Loading…
Reference in New Issue