| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916 |
- package com.datacomsolusindo.migration.data
- import com.datacomsolusindo.cpx_shared_code.entity.*
- import com.datacomsolusindo.cpx_shared_code.service.ApiService
- import com.datacomsolusindo.cpx_shared_code.service.CpDecrypt
- import com.datacomsolusindo.cpx_shared_code.utility.*
- import com.datacomsolusindo.migration.*
- import com.datacomsolusindo.migration.model.MigrationFileData
- import io.azam.ulidj.ULID
- import io.github.semutkecil.simplecriteria.FilterData
- import org.springframework.security.crypto.password.PasswordEncoder
- import org.springframework.stereotype.Service
- import org.springframework.transaction.annotation.Transactional
- import java.time.LocalDateTime
- import java.time.format.DateTimeFormatter
- import java.util.*
- import kotlin.math.log
- import kotlin.time.measureTimedValue
- val temporaryPrepareCallTransactionCallTo: MutableMap<String, Map<String, Any?>?> = mutableMapOf()
- val temporaryPrepareCallTransactionCallFrom: MutableMap<String, String?> = mutableMapOf()
- var temporaryHlrData: MutableMap<String, Map<String, Any?>?> = mutableMapOf()
- @Service
- class FinalizedDataService(
- private val cpDecrypt: CpDecrypt,
- private val passwordEncoder: PasswordEncoder,
- val apiService: ApiService,
- private val insertDataService: InsertDataService,
- private val migrationSettingService: MigrationSettingService
- ) {
- private val logger = SimpleLogger.getLogger(this::class.java)
- fun processData(
- migrationFileData: MigrationFileData
- ): List<MutableMap<String, Any?>> {
- val mappedData = measureTimedValue {
- val fields = migrationFileData.fields
- val fieldMapping = fields.mapValues { it.value.substringAfterLast(".") }
- val hasParent = fieldMapping.any { it.key == "parent_id" }
- val uniqueField = fieldMapping["code"] ?: "id"
- val uniqueFieldId = fieldMapping["id"]
- val historyIndex = buildHistoryIndex(migrationFileData.historyData, uniqueField, uniqueFieldId)
- val historyIndexById =
- buildHistoryIndex(migrationFileData.historyData, uniqueField, uniqueFieldId, byId = true)
- val groupIndex = buildGroupIndex(migrationFileData.groupData, uniqueFieldId ?: uniqueField)
- val fieldRoots = fields.filterValues { !it.contains(".") }
- val joinRoots = fields.filterValues { it.contains(".") }
- migrationFileData.rootData!!
- // .take(10)
- .map { row ->
- buildRow(
- row,
- fieldRoots,
- joinRoots,
- historyIndex,
- historyIndexById,
- groupIndex,
- uniqueField,
- uniqueFieldId
- )
- }.let { data ->
- if (hasParent) {
- data.sortedBy { it["structure"].toString().length }
- } else {
- data.map { postProcessPassword(it) }
- }
- }
- }
- logger.info(
- "finalized data service table ${migrationFileData.table} " +
- "takes time ${mappedData.duration.inWholeMilliseconds}ms " +
- "with all data ${mappedData.value.size}"
- )
- return mappedData.value
- }
- private fun buildHistoryIndex(
- historyData: List<Map<String, Any?>>?,
- uniqueField: String,
- uniqueFieldId: String?,
- byId: Boolean = false
- ): Map<Any?, Map<String, Any?>>? {
- if (historyData == null || uniqueFieldId == null) return null
- return historyData
- .groupBy { if (byId) it[uniqueFieldId] else it[uniqueField] }
- .mapValues { (_, items) ->
- items.maxByOrNull {
- it[uniqueFieldId.removePrefix("history.")]
- ?.toString()
- ?.toIntOrNull() ?: 0
- } as Map<String, Any?>
- }
- }
- private fun buildGroupIndex(groupData: List<Map<String, Any?>>?, key: String): Map<String?, Map<String, Any?>>? {
- return groupData?.associateBy { it[key]?.toString() }
- }
- private fun buildRow(
- row: Map<String, Any?>,
- fieldRoots: Map<String, String>,
- joinRoots: Map<String, String>,
- historyIndex: Map<Any?, Map<String, Any?>>?,
- historyIndexById: Map<Any?, Map<String, Any?>>?,
- groupIndex: Map<String?, Map<String, Any?>>?,
- uniqueField: String,
- uniqueFieldId: String?
- ): MutableMap<String, Any?> {
- val data = mutableMapOf<String, Any?>()
- // Direct fields
- fieldRoots.forEach { (target, source) ->
- data[target] = when {
- target == "pbx__default" -> source
- else -> row[source]
- }
- }
- // Join fields
- joinRoots.forEach { (target, sourceFull) ->
- val value = when {
- sourceFull.startsWith("history.") -> {
- val key = sourceFull.removePrefix("history.")
- val valueHistories = historyIndex
- ?.get(row[uniqueField])
- ?.get(key.substringAfterLast("."))
- valueHistories?.let { valHis ->
- if (target.contains("_")) {
- val codeKey = uniqueField.removePrefix("history.")
- val joinCode = historyIndexById?.get(valHis)?.get(codeKey)
- joinCode ?: valHis
- } else valHis
- }
- }
- sourceFull.startsWith("group.") -> {
- val key = sourceFull.removePrefix("group.")
- val idKey = historyIndex
- ?.get(row[uniqueField])
- ?.get(uniqueFieldId)
- ?: row[uniqueFieldId]
- groupIndex
- ?.get(idKey?.toString())
- ?.get(key.substringAfterLast("."))
- }
- else -> row[sourceFull]
- }
- data[target] = value
- }
- return data
- }
- private fun postProcessPassword(data: MutableMap<String, Any?>): MutableMap<String, Any?> {
- val raw = data["password"]?.toString() ?: return data
- data["password"] = when {
- raw.isBlank() -> ""
- else -> cpDecrypt.decrypt(raw)?.let { plain ->
- tempPassword[plain] ?: passwordEncoder.encode(plain).also {
- tempPassword[plain] = it
- }
- } ?: ""
- }
- return data
- }
- fun finalizeMap(table: String, map: MutableMap<String, Any?>): MutableMap<String, Any?> {
- val mapFinalize: MutableMap<String, Any?> = mutableMapOf()
- map["code"]?.toString()?.let {
- map["code"] = it.ifBlank { UUID.randomUUID().toString().take(6) }
- }
- map["name"]?.toString()?.let {
- map["name"] = it.ifBlank {
- "Auto ${(0..99999).random().toString().padStart(5, '0')}"
- }
- }
- if (table == "phone_user" || table == "cost_center" || table == "organization") {
- map["emailOnOverBudget"] = map["emailOnOverBudget"]?.toString()?.toInt() ?: 0
- }
- map["direction"]?.toString()?.let {
- map["direction"] = if (table == "calltransaction") {
- it.split("").mapNotNull { m ->
- when (m.trim()) {
- "C" -> Direction.INCOMING.ordinal //"C"
- "G" -> Direction.OUTGOING.ordinal //"G"
- "I" -> Direction.INTERNAL.ordinal //"I"
- else -> null
- }
- }.joinToString("")
- } else {
- it.split("").mapNotNull { m ->
- when (m.trim()) {
- "C" -> "C"
- "G" -> "G"
- "I" -> "I"
- else -> null
- }
- }.joinToString("")
- }
- }
- map.filterNot { it.key == "id" || it.key == "structure" }.forEach { (t, u) ->
- when {
- t.contains("__") -> {
- mapFinalize[t] = u
- }
- t.contains("_") -> {
- val isParent = t.startsWith("parent")
- val value = if (t == "pbx_id") {
- findUidByCode("pbx", u ?: "PBX01")
- } else u?.toString()?.let { code ->
- val clazzEntity = if (isParent) table else t.split("_")[0]
- val field = if (t.split("_")[0].lowercase().startsWith("corcos")) "command" else "code"
- findUidByCode(clazzEntity, code, field)
- }
- if (value != null) {
- mapFinalize[t] = value
- }
- }
- else -> {
- mapFinalize[t] = u
- }
- }
- }
- mapFinalize["pin"]?.toString()?.let {
- mapFinalize["pin"] = if (it.isBlank()) null
- else cpDecrypt.decrypt(it)?.let { p ->
- if (table == "phone_user") ToolAes.encrypt(p) else p
- }
- }
- if (table == "calltransaction") {
- val to = mapFinalize["extTransferTo"]?.toString() ?: ""
- val from = mapFinalize["extTransferFrom"]?.toString() ?: ""
- mapFinalize["transferType"] = when {
- to.isBlank() && from.isBlank() -> TransferType.DIRECT.ordinal
- to.isNotBlank() && from.isBlank() -> TransferType.TRANSFER_TO.ordinal
- to.isBlank() && from.isNotBlank() -> TransferType.TRANSFER_FROM.ordinal
- else -> TransferType.TRANSFER_FROM_AND_TRANSFER_TO.ordinal
- }
- }
- if (table == "web_user") {
- defaultProfile?.let { mapFinalize["profile_id"] = it }
- mapFinalize["canRequest"] = 0
- mapFinalize["numberRightsApproval"] = 0
- mapFinalize["requestForOthers"] = 0
- val pinPassword = map["loginPin"]?.toString()?.toInt()?.let { i ->
- if (i == 1) {
- map["phoneUser_id"]?.toString()?.let { uid ->
- findPinPhonePbx(uid)?.let { phoneUserPbx ->
- mapFinalize["pinext_uid"] = phoneUserPbx.first
- ToolAes.decrypt(phoneUserPbx.second)
- }
- }
- } else null
- }
- mapFinalize["password"] = when {
- pinPassword != null -> {
- tempPassword[pinPassword] ?: run {
- val pass = passwordEncoder.encode(pinPassword)
- tempPassword[pinPassword] = pass
- pass
- }
- }
- else -> if (mapFinalize["password"].toString().isEmpty()) {
- tempPassword["12345"] ?: run {
- val pass = passwordEncoder.encode("12345")
- tempPassword["12345"] = pass
- pass
- }
- } else mapFinalize["password"]
- }
- }
- if (table == "corcos") {
- mapFinalize["name"] = "Corcos ${map["name"]}"
- }
- if (table == "trunk") {
- mapFinalize["abonemen"] = 0
- }
- if (table == "organization") {
- mapFinalize["memberLimit"] = 0
- }
- if (table == "phone_user") {
- mapFinalize["asApprover"] = 0
- mapFinalize["bypassApproval"] = 0
- mapFinalize["limitStatus"] = 0
- }
- if (table == "account") {
- mapFinalize["number"] = "9"
- }
- return mapFinalize.filterNot { it.key == "loginPin" }
- .mapValues { v -> v.value?.toString() } as MutableMap<String, Any?>
- }
- private fun findUidByCode(table: String, value: Any, field: String = "code", select: String = "uid"): String? {
- return if (value.toString().isBlank()) null else {
- val tableName = General.toTableName(table)
- val keyCode = "$tableName;$select;$value"
- if (temporaryDataByCode.any { a -> a.key == keyCode }) {
- temporaryDataByCode[keyCode]
- } else {
- var dataUid = try {
- val fd = if (table == "trunk") " AND (subscribed_no != 'new trunk' OR subscribed_no IS NULL) " else " "
- apiService.transaction { em ->
- val result = em.createNativeQuery("SELECT $select FROM $tableName WHERE $field = :$field $fd")
- .setParameter(field, value.toString())
- .resultList
- .first() as String?
- result
- }
- } catch (e: Exception) {
- logger.info("failed find uid $tableName $field $value")
- null
- }
- if (tableName == "corcos" && dataUid == null && migrationSettingService.autoCreateCorcos) {
- dataUid = insertDataService.insertDataWithNativeQuery(tableName, "command", mutableMapOf(
- "command" to value,
- "name" to value,
- "description" to "auto create corcos"
- ))
- }
- temporaryDataByCode[keyCode] = dataUid
- dataUid
- }
- // temporaryDataByCode["$tableName;$select;$value"] ?: run {
- // try {
- // val fd = if (table == "trunk") " AND subscribed_no != 'new trunk' " else " "
- // apiService.transaction { em ->
- // val result = em.createNativeQuery("SELECT $select FROM $tableName WHERE $field = :$field $fd")
- // .setParameter(field, value.toString())
- // .resultList
- // .first() as String?
- // temporaryDataByCode["$tableName;$select;$value"] = result
- // result
- // }
- // } catch (e: Exception) {
- // logger.info("failed find uid $tableName $field $value")
- // null
- // }
- // }
- }
- }
- private fun findCodeByUid(table: String, value: Any, field: String = "uid", select: String = "code"): String? {
- return if (value.toString().isBlank()) null else {
- val tableName = General.toTableName(table)
- val keyCode = "$tableName;$select;$value"
- if (temporaryDataByCode.any { a -> a.key == keyCode }) {
- temporaryDataByCode[keyCode]
- } else {
- try {
- apiService.transaction { em ->
- val result = em.createNativeQuery("SELECT $select FROM $tableName WHERE $field = :$field")
- .setParameter(field, value.toString())
- .resultList
- .first() as String?
- temporaryDataByCode[keyCode] = result
- result
- }
- } catch (e: Exception) {
- temporaryDataByCode[keyCode] = null
- logger.info("failed find code $tableName $field $value")
- null
- }
- }
- // temporaryDataByCode["$tableName;$select;$value"] ?: run {
- // try {
- // apiService.transaction { em ->
- // val result = em.createNativeQuery("SELECT $select FROM $tableName WHERE $field = :$field")
- // .setParameter(field, value.toString())
- // .resultList
- // .first() as String?
- // temporaryDataByCode["$tableName;$select;$value"] = result
- // result
- // }
- // } catch (e: Exception) {
- // logger.info("failed find code $tableName $field $value")
- // null
- // }
- // }
- }
- }
- private val defaultProfile: Any? by lazy {
- apiService.findListPage(
- Rights::class.java,
- listOf("uid"),
- FilterData.filter("name", FilterData.FILTEROP.EQ, "Default")
- ).firstOrNull()?.get("uid")
- }
- private fun findPinPhonePbx(phoneUserCode: String): Pair<String, String>? {
- val key = "${PhoneUserPbx::class.java.simpleName};$phoneUserCode"
- val tmpData = temporaryDataEntity[key] ?: run {
- apiService.findListAll(
- PhoneUserPbx::class.java,
- listOf("pin", "pbx.uid", "phoneUser.code")
- ).forEach { dt ->
- temporaryDataEntity["${PhoneUserPbx::class.java.simpleName};${dt["phoneUser.code"]!!.toString()}"] = dt
- }
- //.associateBy { it["phoneUser.code"]!!.toString() }
- temporaryDataEntity[key]
- }
- return tmpData?.let { it["pbx.uid"].toString() to it["pin"].toString() }
- }
- fun buildToInsertData(table: String, map: MutableMap<String, Any?>, uniqueTable: String?): Int {
- return try {
- val finalizer = finalizeMap(table, map)
- val phoneUserPin = finalizer["pin"]
- val phoneUserExtension = finalizer["extension"]
- val corcosNormal = finalizer["corcosNormal_id"]
- val corcosReducing = finalizer["corcosReducing_id"]
- val corcosBlock = finalizer["corcosBlock_id"]
- // budget
- val budgetAnnual = (finalizer["budget.maxCost"]?.toString()
- ?: finalizer["budget__maxCost"]?.toString())?.toDoubleOrNull()
- val warningAnnual = (finalizer["budget.warnCost"]?.toString()
- ?: finalizer["budget__warnCost"]?.toString())?.toDoubleOrNull()
- val budgetMaxCost = budgetAnnual?.let { max ->
- List(12) { max }.joinToString(";")
- }
- val budgetWarnCost = warningAnnual?.let { warn ->
- val monthBudget = budgetAnnual ?: 0.0
- val warnPercent = (warn / monthBudget) * 100
- List(12) { warnPercent.toInt() }.joinToString(";")
- }
- // phoneUserPbx
- var phoneUserPbxIds: MutableList<String> = mutableListOf()
- val finalMapEntity = when (table) {
- "calltransaction" -> {
- val callMap = prepareDataCallTransaction(finalizer)
- callMap["additionalData1"] =
- "migration-${LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))}"
- callMap
- }
- "phone_user" -> {
- val pbxId = finalizer["pbx.id"]?.toString() ?: finalizer["pbx.list"]?.toString() ?: ""
- val pbxGroup = finalizer["pbx__list"]?.toString()?.split(";")
- ?.mapNotNull { findUidByCode("pbx", it) } ?: listOf()
- if (pbxId.isBlank() && pbxGroup.isEmpty()) {
- finalizer["pbx__default"]?.toString()?.let { pbx ->
- findUidByCode("pbx", pbx)?.let { pbxDefault ->
- phoneUserPbxIds.add(pbxDefault)
- }
- }
- } else {
- if (pbxId.isNotBlank()) {
- phoneUserPbxIds.addAll(pbxId.split(";"))
- }
- if (pbxGroup.isNotEmpty()) {
- phoneUserPbxIds.addAll(pbxGroup)
- }
- }
- val finalMap = finalizer.filterNot { fi ->
- listOf(
- "pbx.list",
- "pbx__list",
- "pbx__default",
- "pbx_id",
- "extension",
- "pin",
- "budget.maxCost",
- "budget__maxCost",
- "budget.warnCost",
- "budget__warnCost",
- "maxCost",
- "warnCost",
- "corcosNormal_id",
- "corcosReducing_id",
- "corcosBlock_id"
- ).any { a -> a == fi.key }
- } as MutableMap<String, Any?>
- finalMap["corcos"] = if (phoneUserPbxIds.isEmpty()) "" else "[${
- phoneUserPbxIds.distinct().joinToString(",") { m ->
- "{\"pbx\":\"$m\"," +
- "\"normal\":\"${corcosNormal ?: ""}\"," +
- "\"reducing\":\"${corcosReducing ?: ""}\"," +
- "\"block\":\"${corcosBlock ?: ""}\"}"
- }
- }]"
- finalMap
- }
- else -> finalizer
- }
- insertDataService.insertDataWithNativeQuery(
- table,
- uniqueTable,
- finalMapEntity,
- functionAfter = { uid, isUpdate ->
- // create budget
- if (BudgetUserType.entries.any { a -> a.name == table.uppercase() }) {
- insertDataService.insertDataWithNativeQuery(
- "budget", uniqueTable = null, mutableMapOf(
- "userType" to BudgetUserType.valueOf(table.uppercase()).ordinal,
- "userUid" to uid,
- "type" to BudgetType.FLAT.ordinal,
- "annualCost" to (budgetAnnual?.let { it * 12 }?.toInt() ?: 0),
- "accumulate" to 0,
- "maxCost" to (budgetMaxCost ?: "0;0;0;0;0;0;0;0;0;0;0;0"),
- "warnCostPercentage" to (budgetWarnCost ?: "0;0;0;0;0;0;0;0;0;0;0;0"),
- "tempCost" to "0;0;0;0;0;0;0;0;0;0;0;0",
- "maxAutoCalculate" to "1;1;1;1;1;1;1;1;1;1;1;1"
- )
- )
- }
- // create phoneUserPbx
- if (phoneUserPbxIds.isNotEmpty()) {
- phoneUserPbxIds.distinct().forEach { pbxId ->
- insertDataService.insertDataWithNativeQuery(
- "phoneuserpbx", uniqueTable = null, mutableMapOf(
- "pin" to phoneUserPin,
- "extension" to phoneUserExtension,
- "pbx_id" to pbxId,
- "phoneUser_id" to uid,
- "corcos_normal_uid" to corcosNormal,
- "corcos_reducing_uid" to corcosReducing,
- "corcos_block_uid" to corcosBlock
- )
- )
- }
- }
- })
- 1
- } catch (e: Exception) {
- // println(Util.mapper.writeValueAsString(map))
- logger.error("failed insert data $table", e)
- 0
- }
- }
- private fun buildRawData(data: MutableMap<String, Any?>): List<Any?> {
- val seg1 = "CDR"
- val seg2 = data["pbx_id"]?.let { findCodeByUid("pbx", it) ?: "" } ?: ""
- val seg3 = data["direction"]?.let { Direction.entries[it.toString().toInt()].code } ?: ""
- val startOfCall = data["startOfCall"]?.toString()?.let {
- LocalDateTime.parse(it, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"))
- }
- val endOfCall = startOfCall?.plusSeconds(data["duration"]?.toString()?.toLong() ?: 0)
- val seg4 = startOfCall?.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) ?: ""
- val seg5 = startOfCall?.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) ?: ""
- val seg6 = endOfCall?.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) ?: ""
- val seg7 = ""
- val seg8 = data["duration"]
- val seg9 = data["accessNumber"] ?: ""
- val seg10 = ""
- val seg11 = data["trunk_id"]?.let { findCodeByUid("trunk", it) ?: "" } ?: ""
- val seg12 = ""
- val seg13 = data["number"] ?: ""
- val seg14 = data["callerNumber"] ?: ""
- val seg15 = data["pin"] ?: ""
- val seg16 = ""
- val seg17 = data["extension"] ?: ""
- val seg18 = data["extTransferFrom"] ?: ""
- val seg19 = data["extTransferTo"] ?: ""
- val seg20 = data["transferType"]?.let {
- when (it as TransferType) {
- TransferType.DIRECT -> "D"
- TransferType.TRANSFER_TO -> "TT"
- TransferType.TRANSFER_FROM -> "TF"
- else -> "F"
- }
- } ?: ""
- val seg21 = "" //data["conferenceType"]?.let { (it as ConferenceType).code } ?: ""
- val seg22 = "" //data["communicationType"]?.let { (it as CommunicationType).code } ?: ""
- val seg23 = data["redirectReason"] ?: ""
- val seg24 = data["terminationCode"] ?: ""
- val seg25 = data["additionalData1"] ?: ""
- val seg26 = data["additionalData2"] ?: ""
- return listOf(
- seg1, seg2, seg3, seg4, seg5, seg6, seg7, seg8, seg9, seg10,
- seg11, seg12, seg13, seg14, seg15, seg16, seg17, seg18, seg19, seg20,
- seg21, seg22, seg23, seg24, seg25, seg26
- )
- }
- private fun prepareDataCallTransaction(data: MutableMap<String, Any?>): MutableMap<String, Any?> {
- data["transferType"] = when {
- (data["extTransferFrom"]?.toString()?.isBlank() ?: false)
- && (data["extTransferTo"]?.toString()?.isBlank() ?: false) -> TransferType.DIRECT
- (data["extTransferFrom"]?.toString()?.isBlank() ?: false)
- && (data["extTransferTo"]?.toString()?.isNotBlank() ?: false) -> TransferType.TRANSFER_TO
- (data["extTransferFrom"]?.toString()?.isNotBlank() ?: false)
- && (data["extTransferTo"]?.toString()?.isBlank() ?: false) -> TransferType.TRANSFER_FROM
- else -> null
- }
- val buildRawData = buildRawData(data)
- val rawData = buildRawData.joinToString(",")
- data["rawData"] = rawData
- getCallTo(buildRawData[12].toString())?.forEach { (t, u) -> data[t] = u }
- //
- // data["area_uid"]?.toString()?.let { area ->
- // val domainFrom = getCallFrom(area, buildRawData[10]?.toString(), buildRawData[1]?.toString())
- // data["zone_uid"]?.toString()?.let {
- // val zoneDomain = if (data["domain"] == domainFrom) "LOC" else "NDD"
- // data["zone_uid"] = findUidByCode("zone", zoneDomain)
- // }
- // }
- data["transferType"]?.let {
- data["transferType"] = (it as TransferType).ordinal
- }
- data.remove("domain")
- return data
- }
- private fun getCallTo(number: String): Map<String, Any?>? {
- val keyCode = "getCall-$number"
- return if (temporaryPrepareCallTransactionCallTo.any { a -> a.key == keyCode })
- temporaryPrepareCallTransactionCallTo[keyCode]
- else {
- val matchedPrefix = temporaryHlrData.entries
- .filter { number.startsWith(it.key) }
- .maxByOrNull { it.key.length }
- ?.value
- val result = matchedPrefix?.let {
- mapOf(
- "prefix" to it["prefix"]?.toString(),
- "provider_to_uid" to it["provider.uid"]?.toString(),
- "area_uid" to it["area.uid"]?.toString(),
- "phone_type" to it["phoneType"]?.let { i -> (i as PhoneType).ordinal },
- "zone_uid" to it["zone.uid"]?.toString(),
- "domain" to it["domain"]?.toString()
- )
- }
- temporaryPrepareCallTransactionCallTo[keyCode] = result
- result
- }
- }
- private fun getCallFrom(areaUid: String, trunkCode: String?, pbxCode: String?): String? {
- val keyCode = "getCallFrom-$areaUid-${trunkCode ?: "#"}-${pbxCode ?: "#"}"
- return if (temporaryPrepareCallTransactionCallFrom.any { a -> a.key == keyCode })
- temporaryPrepareCallTransactionCallFrom[keyCode]
- else {
- try {
- val trunk = trunkCode?.let { findUidByCode("trunk", it, select = "provider_uid") }
- val pbx = pbxCode?.let { findUidByCode("pbx", it, select = "provider_uid") }
- apiService.transaction { em ->
- val hlr = em.createNativeQuery(
- "SELECT TOP 1 domain \n" +
- "FROM hlr\n" +
- "WHERE area_uid = '$areaUid' AND provider_uid = '${trunk ?: pbx ?: "#uid"}' \n"
- ).singleResult as Array<Any?>
- val result = hlr[0].toString()
- temporaryPrepareCallTransactionCallFrom[keyCode] = result
- result
- }
- } catch (e: Exception) {
- temporaryPrepareCallTransactionCallFrom[keyCode] = null
- logger.info("failed get call from attribute area ${areaUid} trunk $trunkCode pbx $pbxCode")
- null
- }
- }
- }
- fun prepareDataCallTransaction() {
- apiService.findListAll(PhoneUser::class.java, select = listOf("uid", "code")).forEach {
- val keyCode = "phone_user;uid;${it["code"] ?: "#"}"
- temporaryDataByCode[keyCode] = it["uid"]?.toString()
- }
- apiService.findListAll(Organization::class.java, select = listOf("uid", "code")).forEach {
- val keyCode = "organization;uid;${it["code"] ?: "#"}"
- temporaryDataByCode[keyCode] = it["uid"]?.toString()
- }
- apiService.findListAll(CostCenter::class.java, select = listOf("uid", "code")).forEach {
- val keyCode = "cost_center;uid;${it["code"] ?: "#"}"
- temporaryDataByCode[keyCode] = it["uid"]?.toString()
- }
- apiService.findListAll(Pbx::class.java, select = listOf("uid", "code")).forEach {
- val keyCode = "pbx;uid;${it["code"] ?: "#"}"
- temporaryDataByCode[keyCode] = it["uid"]?.toString()
- }
- apiService.findListAll(Trunk::class.java, select = listOf("uid", "code")).forEach {
- val keyCode = "trunk;uid;${it["code"] ?: "#"}"
- temporaryDataByCode[keyCode] = it["uid"]?.toString()
- }
- apiService.findListAll(Account::class.java, select = listOf("uid", "code")).forEach {
- val keyCode = "account;uid;${it["code"] ?: "#"}"
- temporaryDataByCode[keyCode] = it["uid"]?.toString()
- }
- // hlr-data
- temporaryHlrData = apiService.findListAll(
- Hlr::class.java,
- select = listOf("prefix", "provider.uid", "area.uid", "phoneType", "zone.uid", "domain")
- ).distinctBy { it["prefix"] }.associateBy { it["prefix"].toString() }.toMutableMap()
- }
- }
- @Service
- @Transactional
- class InsertDataService(
- val apiService: ApiService,
- val migrationSettingService: MigrationSettingService
- ) {
- private fun findParentStructure(table: String, uid: String): String? {
- val parentStructure = temporaryDataByCode["$table;structure;$uid"] ?: run {
- try {
- apiService.transaction { em ->
- val result = em.createNativeQuery("SELECT structure FROM $table WHERE uid = :uid")
- .setParameter("uid", uid)
- .resultList
- .first() as String?
- temporaryDataByCode["$table;structure;$uid"] = result ?: uid
- result ?: uid
- }
- } catch (e: Exception) {
- SimpleLogger.getLogger(this::class.java).error("failed get parent structure $table $uid", e)
- uid
- }
- }
- return parentStructure
- }
- fun insertDataWithNativeQuery(
- table: String,
- uniqueTable: String?,
- mapData: MutableMap<String, Any?>,
- functionAfter: ((uid: String, isUpdate: Boolean) -> Unit)? = null
- ): String? {
- val fieldUnique = when (table) {
- "phoneuserpbx" -> "phone_user_uid;pbx_uid"
- "budget" -> "user_uid"
- else -> uniqueTable
- }
- val fields = if (table == "calltransaction") mutableListOf() else mutableListOf("uid")
- val finalMap = mapData
- .filterNot { it.key == "cpid" }
- .mapValues { it.value?.toString()?.ifEmpty { null } }
- .toMutableMap()
- finalMap.keys.forEach {
- val t = it.replace("_id", "_uid")
- fields.add(t)
- }
- val fieldKey = fieldUnique?.split(";")?.mapNotNull { m -> mapData[m]?.toString() }?.joinToString(";")
- val uidFromDb = temporaryDataByCode["$table;uid;$fieldKey"]
- val uid = uidFromDb ?: ULID.random()
- val isUpdate = uidFromDb != null
- if (isUpdate) {
- finalMap.remove("uid")
- }
- val structure = finalMap["parent_id"]?.let {
- findParentStructure(table, it)?.let { parentUid ->
- fields.add("structure")
- "$parentUid|$uid"
- }
- }
- if (isUpdate) {
- fields.remove("uid")
- }
- val query =
- if (table == "calltransaction") "INSERT INTO $table (${fields.joinToString() { it.camelToSnake() }}) " +
- "VALUES (${fields.joinToString() { ":$it" }})"
- else {
- fieldUnique?.let { fu ->
- val uniqueOn = fu.split(";").joinToString(" AND ") { m -> "t.$m = s.$m" }
- """
- MERGE INTO $table WITH (HOLDLOCK) AS t
- USING (VALUES (${fields.joinToString() { ":$it" }}))
- AS s(${fields.joinToString() { it.camelToSnake() }})
- ON $uniqueOn
- WHEN MATCHED THEN
- UPDATE SET
- ${fields.joinToString(",\n") { "t.${it.camelToSnake()} = s.${it.camelToSnake()}" }}
- WHEN NOT MATCHED THEN
- INSERT (${fields.joinToString { it.camelToSnake() }})
- VALUES (${fields.joinToString { "s.${it.camelToSnake()}" }});
- """.trimIndent()
- } ?: ("INSERT INTO $table (${fields.joinToString() { it.camelToSnake() }}) " +
- "VALUES (${fields.joinToString() { ":$it" }})")
- }
- val sqlNative = apiService.em.createNativeQuery(query)
- if (table != "calltransaction" && !isUpdate) {
- sqlNative.setParameter("uid", uid)
- }
- structure?.let { sqlNative.setParameter("structure", structure) }
- finalMap.forEach { (t, u) -> sqlNative.setParameter(t.replace("_id", "_uid"), u) }
- sqlNative.executeUpdate()
- functionAfter?.invoke(uid, isUpdate)
- return uid
- }
- fun createTableCallTransactionTemporary() {
- try {
- apiService.transaction { em ->
- em.createNativeQuery(
- "IF OBJECT_ID('dbo.calltransaction_temp', 'U') IS NOT NULL\n" +
- "BEGIN\n" +
- " TRUNCATE TABLE dbo.calltransaction_temp;\n" +
- "END\n" +
- "ELSE\n" +
- "BEGIN\n" +
- " SELECT TOP 0 *\n" +
- " INTO dbo.calltransaction_temp\n" +
- " FROM dbo.calltransaction;\n" +
- "END"
- )
- .executeUpdate()
- }
- } catch (e: Exception) {
- SimpleLogger.getLogger(this::class.java).error("failed create table call transaction temporary", e)
- }
- }
- fun updateRawData() {
- try {
- apiService.transaction { em ->
- em.createNativeQuery(
- "UPDATE ct\n" +
- "SET raw_data = CONCAT_WS(',',\n" +
- "\t'CDR',\n" +
- " ISNULL(pbx.code, ''),\n" +
- " CASE \n" +
- " WHEN ct.direction = 0 THEN 'G'\n" +
- " WHEN ct.direction = 1 THEN 'C'\n" +
- " ELSE 'I'\n" +
- " END,\n" +
- " CONVERT(VARCHAR, ct.start_of_call, 120),\n" +
- " CONVERT(VARCHAR, ct.start_of_call, 120),\n" +
- " CONVERT(VARCHAR, DATEADD(SECOND, ct.duration, ct.start_of_call), 120),\n" +
- " '',\n" +
- " ct.duration,\n" +
- " ISNULL(ct.access_number, ''),\n" +
- " '',\n" +
- " ISNULL(trunk.code, ''),\n" +
- " '',\n" +
- " ISNULL(ct.number,''),\n" +
- " ISNULL(ct.caller_number,''),\n" +
- " ISNULL(ct.pin,''),\n" +
- " '',\n" +
- " ISNULL(ct.extension,''),\n" +
- " ISNULL(ct.ext_transfer_from,''),\n" +
- " ISNULL(ct.ext_transfer_to,''),\n" +
- " ISNULL(CASE WHEN ct.transfer_type = 0 THEN 'D'\n" +
- "\tWHEN ct.transfer_type = 1 THEN 'TF'\n" +
- "\tWHEN ct.transfer_type = 2 THEN 'TT'\n" +
- "\tELSE 'F' END,''),\n" +
- " '',\n" +
- " '',\n" +
- " ISNULL(ct.redirect_reason,''),\n" +
- " ISNULL(ct.termination_code,''),\n" +
- " CASE \n" +
- " WHEN ct.additional_data1 = 'migration' THEN ''\n" +
- " ELSE ISNULL(ct.additional_data1,'')\n" +
- " END,\n" +
- " ISNULL(ct.additional_data2,'')\n" +
- ")\n" +
- "FROM calltransaction ct\n" +
- "LEFT JOIN pbx pbx ON pbx.uid = ct.pbx_uid\n" +
- "LEFT JOIN trunk trunk ON trunk.uid = ct.trunk_uid\n" +
- "WHERE ct.raw_data IS NULL OR ct.raw_data = ''"
- )
- }.executeUpdate()
- } catch (e: Exception) {
- SimpleLogger.getLogger(this::class.java).error("failed update raw data blank data", e)
- }
- }
- }
|