diff --git a/.gitignore b/.gitignore index df129be..34a5a1c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ web/node_modules/ web/dist/ log/ +server/src/main/resources/dist/ diff --git a/server/src/main/kotlin/com/bbit/ticket/Application.kt b/server/src/main/kotlin/com/bbit/ticket/Application.kt index e475704..268a69c 100644 --- a/server/src/main/kotlin/com/bbit/ticket/Application.kt +++ b/server/src/main/kotlin/com/bbit/ticket/Application.kt @@ -27,6 +27,8 @@ import com.bbit.ticket.service.openapi.OpenInvoiceTaskWorker import kotlinx.coroutines.runBlocking import io.ktor.server.application.Application import io.ktor.server.auth.authenticate +import io.ktor.server.http.content.singlePageApplication +import io.ktor.server.http.content.vue import io.ktor.server.netty.EngineMain import io.ktor.server.response.respond import io.ktor.server.routing.get @@ -47,7 +49,7 @@ fun Application.module() { configureCors() configureSecurity() configureDatabase() - configureRedis() +// configureRedis() runBlocking { DatabaseInitializer.initialize() SeedData.seed() @@ -58,6 +60,10 @@ fun Application.module() { get("/health") { call.respond(ok(mapOf("status" to "UP", "service" to AppConfig.app.name))) } + singlePageApplication { + useResources = true + vue("dist") + } route("/api") { registerAuthRoutes() registerUserRoutes() diff --git a/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/EnterpriseManageDao.kt b/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/EnterpriseManageDao.kt index f802212..877769c 100644 --- a/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/EnterpriseManageDao.kt +++ b/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/EnterpriseManageDao.kt @@ -105,10 +105,33 @@ object EnterpriseManageDao { } } - fun digitalAccountsForEnterprise(enterpriseId: Uuid): List = - PtDigitalAccountTable.selectAll() - .where { (PtDigitalAccountTable.enterpriseId eq enterpriseId) and PtDigitalAccountTable.deletedAt.isNull() } + fun digitalAccountsForEnterprise( + enterpriseId: Uuid, + account: String?, + status: String?, + page: Int, + pageSize: Int, + ): PageResult { + val where = digitalAccountWhere(enterpriseId, account, status) + val total = PtDigitalAccountTable.selectAll().where { where }.count() + val rows = PtDigitalAccountTable.selectAll() + .where { where } .orderBy(PtDigitalAccountTable.createdAt, SortOrder.DESC) + .limit(pageSize) + .offset(pageOffset(page, pageSize)) + .map { it.toDigitalAccountItem() } + return PageResult(rows, page, pageSize, total) + } + + fun digitalAccountOptionsForEnterprise( + enterpriseId: Uuid, + account: String?, + limit: Int, + ): List = + PtDigitalAccountTable.selectAll() + .where { digitalAccountWhere(enterpriseId, account, "ENABLED") } + .orderBy(PtDigitalAccountTable.createdAt, SortOrder.DESC) + .limit(limit) .map { it.toDigitalAccountItem() } fun digitalAccount(id: Uuid): ResultRow? = @@ -134,6 +157,18 @@ object EnterpriseManageDao { } .singleOrNull() + private fun digitalAccountWhere(enterpriseId: Uuid, account: String?, status: String?): Op { + var where: Op = + (PtDigitalAccountTable.enterpriseId eq enterpriseId) and PtDigitalAccountTable.deletedAt.isNull() + account?.trim()?.takeIf { it.isNotEmpty() }?.let { + where = where and (PtDigitalAccountTable.account like "%$it%") + } + status?.trim()?.takeIf { it.isNotEmpty() }?.let { + where = where and (PtDigitalAccountTable.status eq it.uppercase()) + } + return where + } + fun upsertDigitalAccount(enterpriseId: Uuid, item: DigitalAccountInfo): Uuid { val existing = PtDigitalAccountTable.selectAll() .where { diff --git a/server/src/main/kotlin/com/bbit/ticket/database/piaotong/HistoryInvoiceBasicTable.kt b/server/src/main/kotlin/com/bbit/ticket/database/piaotong/HistoryInvoiceBasicTable.kt index 7d341c3..63c1f32 100644 --- a/server/src/main/kotlin/com/bbit/ticket/database/piaotong/HistoryInvoiceBasicTable.kt +++ b/server/src/main/kotlin/com/bbit/ticket/database/piaotong/HistoryInvoiceBasicTable.kt @@ -1,4 +1,4 @@ -package com.bbit.ticket.database.piaotong +package com.bbit.ticket.database.piaotong import org.jetbrains.exposed.v1.core.Table import org.jetbrains.exposed.v1.javatime.timestampWithTimeZone @@ -306,13 +306,13 @@ object HistoryInvoiceBasicTable : Table("history_invoice_basic") { .nullable() /** - * 冲红状态 + * 红冲状态 * - * NOT_RED:未冲红 - * ALREADY_RED:已冲红 - * REDING:冲红中 - * RED_FAIL:冲红失败 - * PART_RED:部分冲红 + * NOT_RED:未红冲 + * ALREADY_RED:已红冲 + * REDING:红冲中 + * RED_FAIL:红冲失败 + * PART_RED:部分红冲 */ val redFlag = varchar("red_flag", 32) .nullable() @@ -453,3 +453,4 @@ object HistoryInvoiceBasicTable : Table("history_invoice_basic") { override val primaryKey = PrimaryKey(id) } + diff --git a/server/src/main/kotlin/com/bbit/ticket/database/piaotong/HistoryInvoiceRedTable.kt b/server/src/main/kotlin/com/bbit/ticket/database/piaotong/HistoryInvoiceRedTable.kt index c90550e..87f6ee7 100644 --- a/server/src/main/kotlin/com/bbit/ticket/database/piaotong/HistoryInvoiceRedTable.kt +++ b/server/src/main/kotlin/com/bbit/ticket/database/piaotong/HistoryInvoiceRedTable.kt @@ -1,4 +1,4 @@ -@file:OptIn(ExperimentalUuidApi::class) +@file:OptIn(ExperimentalUuidApi::class) package com.bbit.ticket.database.piaotong @@ -26,13 +26,13 @@ object HistoryInvoiceRedTable : Table("history_invoice_red") { /** * 发票代码 - * 需冲红的原发票代码,冲红增值税发票管理系统开具的发票或数电纸质发票时必填 + * 需红冲的原发票代码,红冲增值税发票管理系统开具的发票或数电纸质发票时必填 */ val invoiceCode = varchar("invoice_code", 12).nullable() /** * 发票请求流水号 - * 需冲红的原发票号码,冲红增值税发票管理系统开具的发票或数电纸质发票时必填 + * 需红冲的原发票号码,红冲增值税发票管理系统开具的发票或数电纸质发票时必填 */ val invoiceNo = varchar("invoice_no", 8).nullable() @@ -42,7 +42,7 @@ object HistoryInvoiceRedTable : Table("history_invoice_red") { val invoiceReqSerialNo = varchar("invoice_req_serial_no", 20) /** - * 冲红原因 + * 红冲原因 * 01:开票有误 * 02:销货退回 * 03:服务中止 @@ -61,9 +61,9 @@ object HistoryInvoiceRedTable : Table("history_invoice_red") { * 81:数电发票(增值税专用发票) * 82:数电发票(普通发票)。 * 默认蓝票的发票种类代码。 - * 此字段目的解决数电发票冲红增值税发票,只有企业不再使用增值税系统时才可以跨票种冲红。 - * 数电发票(普通发票)可以冲红数电发票(普通发票)、增值税电子普通发票、增值税纸质普通发票。 - * 数电发票(增值税专用发票)可以冲红数电发票(增值税专用发票)、增值税电子专用发票、增值税纸质专用发票。 + * 此字段目的解决数电发票红冲增值税发票,只有企业不再使用增值税系统时才可以跨票种红冲。 + * 数电发票(普通发票)可以红冲数电发票(普通发票)、增值税电子普通发票、增值税纸质普通发票。 + * 数电发票(增值税专用发票)可以红冲数电发票(增值税专用发票)、增值税电子专用发票、增值税纸质专用发票。 */ val invoiceKind = varchar("invoice_kind", 2).nullable() @@ -104,3 +104,4 @@ object HistoryInvoiceRedTable : Table("history_invoice_red") { override val primaryKey = PrimaryKey(id) } + diff --git a/server/src/main/kotlin/com/bbit/ticket/database/piaotong/OpenInvoiceTaskTable.kt b/server/src/main/kotlin/com/bbit/ticket/database/piaotong/OpenInvoiceTaskTable.kt index cabf024..17521c6 100644 --- a/server/src/main/kotlin/com/bbit/ticket/database/piaotong/OpenInvoiceTaskTable.kt +++ b/server/src/main/kotlin/com/bbit/ticket/database/piaotong/OpenInvoiceTaskTable.kt @@ -16,7 +16,6 @@ object OpenInvoiceTaskTable : Table("open_invoice_task") { val taxAccount = varchar("tax_account", 64).nullable() val taskType = varchar("task_type", 32) val sourceType = varchar("source_type", 32) - val runMode = varchar("run_mode", 16) val invoiceReqSerialNo = varchar("invoice_req_serial_no", 20) val batchNo = varchar("batch_no", 64).nullable() val status = varchar("status", 32) diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/openapi/OpenInvoiceTaskDto.kt b/server/src/main/kotlin/com/bbit/ticket/entity/openapi/OpenInvoiceTaskDto.kt index 2241ae6..ba358b3 100644 --- a/server/src/main/kotlin/com/bbit/ticket/entity/openapi/OpenInvoiceTaskDto.kt +++ b/server/src/main/kotlin/com/bbit/ticket/entity/openapi/OpenInvoiceTaskDto.kt @@ -9,7 +9,6 @@ data class OpenInvoiceTaskSubmitResponse( val invoiceReqSerialNo: String, val status: String, val taskType: String, - val runMode: String, ) @Serializable @@ -37,7 +36,6 @@ data class OpenInvoiceTaskItem( val account: String? = null, val taskType: String, val sourceType: String, - val runMode: String, val invoiceReqSerialNo: String, val batchNo: String? = null, val status: String, diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/request/CreateRedInvoiceRequest.kt b/server/src/main/kotlin/com/bbit/ticket/entity/request/CreateRedInvoiceRequest.kt index f13475d..270422a 100644 --- a/server/src/main/kotlin/com/bbit/ticket/entity/request/CreateRedInvoiceRequest.kt +++ b/server/src/main/kotlin/com/bbit/ticket/entity/request/CreateRedInvoiceRequest.kt @@ -1,4 +1,4 @@ -package com.bbit.ticket.entity.request +package com.bbit.ticket.entity.request import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -28,7 +28,7 @@ data class CreateRedInvoiceRequest( /** * 蓝票代码 * - * 冲红税控发票或数电纸质发票时必填 + * 红冲税控发票或数电纸质发票时必填 */ @SerialName("blueInvoiceCode") val blueInvoiceCode: String? = null, @@ -36,7 +36,7 @@ data class CreateRedInvoiceRequest( /** * 蓝票号码 * - * 冲红税控发票或数电纸质发票时必填 + * 红冲税控发票或数电纸质发票时必填 */ @SerialName("blueInvoiceNo") val blueInvoiceNo: String? = null, @@ -98,4 +98,4 @@ data class CreateRedInvoiceRequest( */ @SerialName("definedData") val definedData: String? = null -) \ No newline at end of file +) diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/request/InitRedInvoiceConfirmRequest.kt b/server/src/main/kotlin/com/bbit/ticket/entity/request/InitRedInvoiceConfirmRequest.kt index 888e617..46c9b36 100644 --- a/server/src/main/kotlin/com/bbit/ticket/entity/request/InitRedInvoiceConfirmRequest.kt +++ b/server/src/main/kotlin/com/bbit/ticket/entity/request/InitRedInvoiceConfirmRequest.kt @@ -1,4 +1,4 @@ -package com.bbit.ticket.entity.request +package com.bbit.ticket.entity.request import kotlinx.serialization.Serializable @@ -20,25 +20,25 @@ data class InitRedInvoiceConfirmRequest( /** * 税控蓝字发票代码(10或12位) - * 冲红增值税发票管理系统开具的发票或数电纸票时必填 + * 红冲增值税发票管理系统开具的发票或数电纸票时必填 */ val invoiceCode: String? = null, /** * 税控蓝字发票号码(8位) - * 冲红增值税发票管理系统开具的发票或数电纸票时必填 + * 红冲增值税发票管理系统开具的发票或数电纸票时必填 */ val invoiceNo: String? = null, /** * 蓝字数电票号码(20位) - * 冲红数电发票时必填 + * 红冲数电发票时必填 */ val blueAllEleInvNo: String? = null, /** * 蓝字发票开票日期(yyyyMMdd) - * 冲红非票通平台开具的发票时必填 + * 红冲非票通平台开具的发票时必填 */ val blueInvoiceDate: String? = null, @@ -48,4 +48,4 @@ data class InitRedInvoiceConfirmRequest( * 若不传:优先取蓝票开票账号,否则取企业当前账号 */ val account: String? = null -) \ No newline at end of file +) diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/request/QuickRedInvoiceRequest.kt b/server/src/main/kotlin/com/bbit/ticket/entity/request/QuickRedInvoiceRequest.kt index 236ac4c..c431238 100644 --- a/server/src/main/kotlin/com/bbit/ticket/entity/request/QuickRedInvoiceRequest.kt +++ b/server/src/main/kotlin/com/bbit/ticket/entity/request/QuickRedInvoiceRequest.kt @@ -1,10 +1,10 @@ -package com.bbit.ticket.entity.request +package com.bbit.ticket.entity.request import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable /** - * 快捷冲红数电发票请求 + * 快捷红冲数电发票请求 */ @Serializable data class QuickRedInvoiceRequest( @@ -29,7 +29,7 @@ data class QuickRedInvoiceRequest( /** * 原发票代码 * - * 冲红增值税系统发票或数电纸质发票时必填 + * 红冲增值税系统发票或数电纸质发票时必填 */ @SerialName("invoiceCode") val invoiceCode: String? = null, @@ -37,7 +37,7 @@ data class QuickRedInvoiceRequest( /** * 原发票号码 * - * 冲红增值税系统发票或数电纸质发票时必填 + * 红冲增值税系统发票或数电纸质发票时必填 */ @SerialName("invoiceNo") val invoiceNo: String? = null, @@ -45,7 +45,7 @@ data class QuickRedInvoiceRequest( /** * 原数电发票号码 * - * 冲红数电发票时必填 + * 红冲数电发票时必填 */ @SerialName("blueAllEleInvNo") val blueAllEleInvNo: String? = null, @@ -56,14 +56,14 @@ data class QuickRedInvoiceRequest( * 格式:yyyyMMdd * * 场景: - * 冲红非票通平台开具的发票时必填, + * 红冲非票通平台开具的发票时必填, * 税局会结合该日期与数电发票号码拉取原票 */ @SerialName("blueInvoiceDate") val blueInvoiceDate: String? = null, /** - * 冲红原因 + * 红冲原因 * * 默认值:01 * @@ -108,7 +108,7 @@ data class QuickRedInvoiceRequest( * * 默认取蓝票票种 * - * 用于跨票种冲红场景 + * 用于跨票种红冲场景 */ @SerialName("invoiceKind") val invoiceKind: String? = null, @@ -150,4 +150,4 @@ data class QuickRedInvoiceRequest( */ @SerialName("definedData") val definedData: String? = null -) \ No newline at end of file +) diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/request/RedCreateRequest.kt b/server/src/main/kotlin/com/bbit/ticket/entity/request/RedCreateRequest.kt index 11812de..0c0b575 100644 --- a/server/src/main/kotlin/com/bbit/ticket/entity/request/RedCreateRequest.kt +++ b/server/src/main/kotlin/com/bbit/ticket/entity/request/RedCreateRequest.kt @@ -1,4 +1,4 @@ -package com.bbit.ticket.entity.request +package com.bbit.ticket.entity.request import kotlinx.serialization.Serializable @@ -7,11 +7,11 @@ data class RedCreateRequest( val historyId: String, /** - * 平台数电账号 ID。企业管理员发起冲红时用于指定开票员。 + * 平台数电账号 ID。企业管理员发起红冲时用于指定开票员。 */ val digitalAccountId: String? = null, /** - * 冲红原因 + * 红冲原因 * * 默认值:01 * @@ -26,3 +26,4 @@ data class RedCreateRequest( val takerTel: String? = null, val takerEmail: String? = null, ) + diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceHistoryItem.kt b/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceHistoryItem.kt index 84e3cbd..0b0a191 100644 --- a/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceHistoryItem.kt +++ b/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceHistoryItem.kt @@ -1,4 +1,4 @@ -@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class) +@file:OptIn(kotlin.uuid.ExperimentalUuidApi::class) package com.bbit.ticket.entity.response @@ -100,7 +100,7 @@ data class InvoiceHistoryItem( // ===== 发票状态标记 ===== /** 作废状态 */ val invalidFlag: String? = null, - /** 冲红状态 */ + /** 红冲状态 */ val redFlag: String? = null, // ===== 人员信息 ===== @@ -149,3 +149,4 @@ data class InvoiceHistoryItem( /** 删除标记 */ val invDeletedFlag: String? = null, ) + diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceQueryResponse.kt b/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceQueryResponse.kt index f71691f..d326aed 100644 --- a/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceQueryResponse.kt +++ b/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceQueryResponse.kt @@ -1,4 +1,4 @@ -package com.bbit.ticket.entity.response +package com.bbit.ticket.entity.response import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -168,13 +168,13 @@ data class InvoiceInfo( val invalidFlag: String, /** - * 冲红标志 + * 红冲标志 * - * NOT_RED:未冲红 - * ALREADY_RED:已冲红 - * REDING:冲红中 - * RED_FAIL:冲红失败 - * PART_RED:部分冲红 + * NOT_RED:未红冲 + * ALREADY_RED:已红冲 + * REDING:红冲中 + * RED_FAIL:红冲失败 + * PART_RED:部分红冲 */ @SerialName("redFlag") val redFlag: String, @@ -345,4 +345,4 @@ data class InvoiceItem( */ @SerialName("itemNo") val itemNo: String -) \ No newline at end of file +) diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceResponse.kt b/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceResponse.kt index a6712bc..1c697c4 100644 --- a/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceResponse.kt +++ b/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceResponse.kt @@ -1,4 +1,4 @@ -package com.bbit.ticket.entity.response +package com.bbit.ticket.entity.response import com.bbit.ticket.entity.request.InvoiceItem import kotlinx.serialization.SerialName @@ -187,12 +187,12 @@ data class GetInvoiceInfoResponse( val invalidFlag: String? = null, /** - * 冲红状态 - * NOT_RED:未冲红 - * ALREADY_RED:已冲红 - * REDING:冲红中 - * RED_FAIL:冲红失败 - * PART_RED:部分冲红 + * 红冲状态 + * NOT_RED:未红冲 + * ALREADY_RED:已红冲 + * REDING:红冲中 + * RED_FAIL:红冲失败 + * PART_RED:部分红冲 */ val redFlag: String? = null, @@ -344,4 +344,4 @@ data class GetInvoiceInfoItem( /** 蓝字发票明细序号(红票场景) */ val blueInvOrderNo: String? = null -) \ No newline at end of file +) diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/response/QuickRedInvoiceResponse.kt b/server/src/main/kotlin/com/bbit/ticket/entity/response/QuickRedInvoiceResponse.kt index e2ad03a..d64c646 100644 --- a/server/src/main/kotlin/com/bbit/ticket/entity/response/QuickRedInvoiceResponse.kt +++ b/server/src/main/kotlin/com/bbit/ticket/entity/response/QuickRedInvoiceResponse.kt @@ -1,10 +1,10 @@ -package com.bbit.ticket.entity.response +package com.bbit.ticket.entity.response import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable /** - * 快捷冲红数电发票响应 + * 快捷红冲数电发票响应 */ @Serializable data class QuickRedInvoiceResponse( @@ -51,4 +51,4 @@ data class QuickRedInvoiceResponse( */ @SerialName("redApplySerialNo") val redApplySerialNo: String? = null -) \ No newline at end of file +) diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/response/RedInvoiceInfoResponse.kt b/server/src/main/kotlin/com/bbit/ticket/entity/response/RedInvoiceInfoResponse.kt index 1c847a2..b34f3ce 100644 --- a/server/src/main/kotlin/com/bbit/ticket/entity/response/RedInvoiceInfoResponse.kt +++ b/server/src/main/kotlin/com/bbit/ticket/entity/response/RedInvoiceInfoResponse.kt @@ -1,16 +1,16 @@ -package com.bbit.ticket.entity.response +package com.bbit.ticket.entity.response import kotlinx.serialization.Serializable /** * 红票申请信息 * - * 对应 [HistoryInvoiceRedTable] 的冲红申请字段, + * 对应 [HistoryInvoiceRedTable] 的红冲申请字段, * 用于红票详情弹窗展示。 */ @Serializable data class RedInvoiceInfoResponse( - /** 冲红原因:01=开票有误 02=销货退回 03=服务中止 04=销售折让 */ + /** 红冲原因:01=开票有误 02=销货退回 03=服务中止 04=销售折让 */ val redReason: String, /** 收票人名称 */ val takerName: String? = null, @@ -19,3 +19,4 @@ data class RedInvoiceInfoResponse( /** 收票人邮箱 */ val takerEmail: String? = null, ) + diff --git a/server/src/main/kotlin/com/bbit/ticket/route/openapi/registerOpenInvoiceTaskRoutes.kt b/server/src/main/kotlin/com/bbit/ticket/route/openapi/registerOpenInvoiceTaskRoutes.kt index 2ad13b6..79a4809 100644 --- a/server/src/main/kotlin/com/bbit/ticket/route/openapi/registerOpenInvoiceTaskRoutes.kt +++ b/server/src/main/kotlin/com/bbit/ticket/route/openapi/registerOpenInvoiceTaskRoutes.kt @@ -8,27 +8,13 @@ import io.ktor.server.routing.Route import io.ktor.server.routing.post fun Route.registerOpenInvoiceTaskRoutes() { - post("/test") { + post { val principal = call.requireOpenApiPrincipal() val request = call.receive() - call.respondOpenApi(principal, "blue-invoice-task.test", null) { + call.respondOpenApi(principal, "blue-invoice-task.create", null) { OpenInvoiceTaskService.createIssueTask( principal = principal, request = request, - runMode = OpenInvoiceTaskService.MODE_SIMULATED, - sourceType = OpenInvoiceTaskService.SOURCE_TEST, - ) - } - } - - post("/production") { - val principal = call.requireOpenApiPrincipal() - val request = call.receive() - call.respondOpenApi(principal, "blue-invoice-task.production", null) { - OpenInvoiceTaskService.createIssueTask( - principal = principal, - request = request, - runMode = OpenInvoiceTaskService.MODE_REAL, ) } } diff --git a/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerOpenInvoiceTaskManageRoutes.kt b/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerOpenInvoiceTaskManageRoutes.kt index aec2ad2..9276eca 100644 --- a/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerOpenInvoiceTaskManageRoutes.kt +++ b/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerOpenInvoiceTaskManageRoutes.kt @@ -21,7 +21,6 @@ fun Route.registerOpenInvoiceTaskManageRoutes() { digitalAccountId = call.request.queryParameters["digitalAccountId"], status = call.request.queryParameters["status"], sourceType = call.request.queryParameters["sourceType"], - runMode = call.request.queryParameters["runMode"], page = call.request.queryParameters["page"]?.toIntOrNull() ?: 1, pageSize = call.request.queryParameters["pageSize"]?.toIntOrNull() ?: 20, ) diff --git a/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerPTAuthRoutes.kt b/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerPTAuthRoutes.kt index 15ef8f6..ee0f6b5 100644 --- a/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerPTAuthRoutes.kt +++ b/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerPTAuthRoutes.kt @@ -12,6 +12,8 @@ import com.bbit.ticket.entity.request.UpdateDigitalAccountStatusRequest import com.bbit.ticket.entity.request.UpdateInvoiceSettingRequest import com.bbit.ticket.service.piaotong.PTAuthService import com.bbit.ticket.service.piaotong.PTConfigService +import com.bbit.ticket.utils.queryInt +import com.bbit.ticket.utils.queryString import com.bbit.ticket.utils.requireCurrentUser import io.ktor.server.request.receive import io.ktor.server.routing.Route @@ -59,7 +61,23 @@ fun Route.registerPTAuthRoutes() { get("/digital-accounts") { call.respondPt("查询数电账号失败") { - PTConfigService.listDigitalAccounts(call.requireCurrentUser()) + PTConfigService.listDigitalAccounts( + user = call.requireCurrentUser(), + account = call.queryString("account"), + status = call.queryString("status"), + page = call.queryInt("page", 1), + pageSize = call.queryInt("pageSize", 20), + ) + } + } + + get("/digital-accounts/options") { + call.respondPt("查询数电账号选项失败") { + PTConfigService.listDigitalAccountOptions( + user = call.requireCurrentUser(), + account = call.queryString("account"), + limit = call.queryInt("limit", 200), + ) } } diff --git a/server/src/main/kotlin/com/bbit/ticket/service/openapi/OpenInvoiceTaskService.kt b/server/src/main/kotlin/com/bbit/ticket/service/openapi/OpenInvoiceTaskService.kt index 3fd0e75..c832b9f 100644 --- a/server/src/main/kotlin/com/bbit/ticket/service/openapi/OpenInvoiceTaskService.kt +++ b/server/src/main/kotlin/com/bbit/ticket/service/openapi/OpenInvoiceTaskService.kt @@ -56,9 +56,6 @@ object OpenInvoiceTaskService { const val TASK_ISSUE_BLUE = "ISSUE_BLUE" const val TASK_QUERY_BLUE = "QUERY_BLUE" const val SOURCE_SINGLE = "SINGLE" - const val SOURCE_TEST = "TEST" - const val MODE_REAL = "REAL" - const val MODE_SIMULATED = "SIMULATED" private const val STATUS_PENDING = "PENDING" private const val STATUS_PROCESSING = "PROCESSING" @@ -75,7 +72,6 @@ object OpenInvoiceTaskService { suspend fun createIssueTask( principal: OpenApiPrincipal, request: OpenBlueInvoiceCreateRequest, - runMode: String, sourceType: String = SOURCE_SINGLE, batchNo: String? = null, ): OpenInvoiceTaskSubmitResponse { @@ -97,12 +93,6 @@ object OpenInvoiceTaskService { .singleOrNull() } if (existing != null) { - if (existing[OpenInvoiceTaskTable.runMode] != runMode) { - throw BizException( - ErrorCode.BAD_REQUEST.code, - "invoiceReqSerialNo 已存在 ${existing[OpenInvoiceTaskTable.runMode]} 任务,不能重复创建 $runMode 任务", - ) - } return existing.toSubmitResponse() } @@ -129,7 +119,6 @@ object OpenInvoiceTaskService { it[taxAccount] = principal.taxAccount it[taskType] = TASK_ISSUE_BLUE it[OpenInvoiceTaskTable.sourceType] = sourceType - it[OpenInvoiceTaskTable.runMode] = runMode it[OpenInvoiceTaskTable.invoiceReqSerialNo] = invoiceReqSerialNo it[OpenInvoiceTaskTable.batchNo] = batchNo it[status] = STATUS_PENDING @@ -146,19 +135,12 @@ object OpenInvoiceTaskService { } .single() } - if (task[OpenInvoiceTaskTable.runMode] != runMode) { - throw BizException( - ErrorCode.BAD_REQUEST.code, - "invoiceReqSerialNo 已存在 ${task[OpenInvoiceTaskTable.runMode]} 任务,不能重复创建 $runMode 任务", - ) - } return OpenInvoiceTaskSubmitResponse( taskId = task[OpenInvoiceTaskTable.id].toString(), invoiceReqSerialNo = invoiceReqSerialNo, status = task[OpenInvoiceTaskTable.status], taskType = TASK_ISSUE_BLUE, - runMode = runMode, ) } @@ -201,7 +183,6 @@ object OpenInvoiceTaskService { digitalAccountId: String?, status: String?, sourceType: String?, - runMode: String?, page: Int, pageSize: Int, ): PageResult = dbQuery { @@ -215,9 +196,6 @@ object OpenInvoiceTaskService { sourceType?.takeIf { it.isNotBlank() }?.let { where = where and (OpenInvoiceTaskTable.sourceType eq it) } - runMode?.takeIf { it.isNotBlank() }?.let { - where = where and (OpenInvoiceTaskTable.runMode eq it) - } val accountRows = PtDigitalAccountTable.selectAll() .where { accountScope(user) } .associateBy { it[PtDigitalAccountTable.id] } @@ -290,18 +268,13 @@ object OpenInvoiceTaskService { private suspend fun processIssueTask(task: ResultRow) { val taskId = task[OpenInvoiceTaskTable.id] - val runMode = task[OpenInvoiceTaskTable.runMode] val request = task[OpenInvoiceTaskTable.requestBody] ?.let { myJson.decodeFromString(it) } ?: return failTask(taskId, "REQUEST_BODY_NULL", "任务请求体为空") val askRequest = request.toAskInvoiceRequest(task) createHistoryPlaceholder(task, askRequest) try { - if (runMode == MODE_SIMULATED) { - delay(2000) - } else { - PTApi.invoiceBlue(askRequest) - } + PTApi.invoiceBlue(askRequest) completeIssueTask(task) } catch (e: PTException) { failTask(taskId, e.code, e.message) @@ -314,31 +287,23 @@ object OpenInvoiceTaskService { } private suspend fun processQueryTask(task: ResultRow) { - val taskId = task[OpenInvoiceTaskTable.id] - val runMode = task[OpenInvoiceTaskTable.runMode] val invoiceReqSerialNo = task[OpenInvoiceTaskTable.invoiceReqSerialNo] try { - val (code, message) = if (runMode == MODE_SIMULATED) { - delay(2000) - simulatedQueryCode(invoiceReqSerialNo, task[OpenInvoiceTaskTable.pollCount]) to null - } else { - val res = PTApi.queryInvoiceInfo( - QueryInvoiceRequest( - taxpayerNum = task[OpenInvoiceTaskTable.taxpayerNum], - invoiceReqSerialNo = invoiceReqSerialNo, - ) + val res = PTApi.queryInvoiceInfo( + QueryInvoiceRequest( + taxpayerNum = task[OpenInvoiceTaskTable.taxpayerNum], + invoiceReqSerialNo = invoiceReqSerialNo, + ) + ) + dbQuery { + BlueInvoiceDao.upsertInvoiceInfo( + task[OpenInvoiceTaskTable.userId], + res, + task[OpenInvoiceTaskTable.enterpriseId], + task[OpenInvoiceTaskTable.digitalAccountId], ) - dbQuery { - BlueInvoiceDao.upsertInvoiceInfo( - task[OpenInvoiceTaskTable.userId], - res, - task[OpenInvoiceTaskTable.enterpriseId], - task[OpenInvoiceTaskTable.digitalAccountId], - ) - } - res.code to res.msg } - handleQueryCode(task, code, message) + handleQueryCode(task, res.code, res.msg) } catch (e: PTException) { retryOrFail(task, e.code, e.message) } catch (e: Exception) { @@ -368,7 +333,6 @@ object OpenInvoiceTaskService { it[taxAccount] = task[OpenInvoiceTaskTable.taxAccount] it[taskType] = TASK_QUERY_BLUE it[sourceType] = task[OpenInvoiceTaskTable.sourceType] - it[runMode] = task[OpenInvoiceTaskTable.runMode] it[OpenInvoiceTaskTable.invoiceReqSerialNo] = invoiceReqSerialNo it[batchNo] = task[OpenInvoiceTaskTable.batchNo] it[status] = STATUS_PENDING @@ -660,15 +624,6 @@ object OpenInvoiceTaskService { orderList = orderList, ) - private fun simulatedQueryCode(invoiceReqSerialNo: String, pollCount: Int): String = - when { - invoiceReqSerialNo.contains("3999", ignoreCase = true) -> AUTH_REQUIRED_CODE - invoiceReqSerialNo.contains("FAIL", ignoreCase = true) -> "9999" - pollCount <= 0 -> "7777" - pollCount == 1 -> "6666" - else -> "0000" - } - private fun historyCode(code: String): String = if (code.length <= 8) code else HISTORY_FAILED_CODE @@ -706,7 +661,6 @@ object OpenInvoiceTaskService { invoiceReqSerialNo = this[OpenInvoiceTaskTable.invoiceReqSerialNo], status = this[OpenInvoiceTaskTable.status], taskType = this[OpenInvoiceTaskTable.taskType], - runMode = this[OpenInvoiceTaskTable.runMode], ) private fun ResultRow.toTaskItem(account: String?, historyMessage: String?): OpenInvoiceTaskItem = @@ -717,7 +671,6 @@ object OpenInvoiceTaskService { account = account, taskType = this[OpenInvoiceTaskTable.taskType], sourceType = this[OpenInvoiceTaskTable.sourceType], - runMode = this[OpenInvoiceTaskTable.runMode], invoiceReqSerialNo = this[OpenInvoiceTaskTable.invoiceReqSerialNo], batchNo = this[OpenInvoiceTaskTable.batchNo], status = this[OpenInvoiceTaskTable.status], diff --git a/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTConfigService.kt b/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTConfigService.kt index d6511a5..3101e9e 100644 --- a/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTConfigService.kt +++ b/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTConfigService.kt @@ -6,6 +6,7 @@ import com.bbit.ticket.dao.piaotong.EnterpriseManageDao import com.bbit.ticket.dao.system.UserDao import com.bbit.ticket.database.piaotong.PtDigitalAccountTable import com.bbit.ticket.database.system.SysUserTable +import com.bbit.ticket.entity.common.PageResult import com.bbit.ticket.entity.request.CreateDigitalAccountRequest import com.bbit.ticket.entity.request.QueryDigitalAccountListRequest import com.bbit.ticket.entity.request.QueryEnterpriseBankAccountRequest @@ -62,15 +63,42 @@ object PTConfigService { return PTAuthService.queryEnterpriseBankInfo(QueryEnterpriseBankAccountRequest(taxpayerNum)).bankList } - suspend fun listDigitalAccounts(user: CurrentUser): List = dbQuery { + suspend fun listDigitalAccounts( + user: CurrentUser, + account: String?, + status: String?, + page: Int, + pageSize: Int, + ): PageResult = dbQuery { when { user.isSuperAdmin || user.isEnterpriseAdmin -> { - EnterpriseManageDao.digitalAccountsForEnterprise(requireEnterpriseId(user)) + EnterpriseManageDao.digitalAccountsForEnterprise(requireEnterpriseId(user), account, status, page, pageSize) } user.isDigitalOperator -> { val id = user.digitalAccountId ?: throw BizException(ErrorCode.BAD_REQUEST.code, "当前账号未绑定数电账号") - EnterpriseManageDao.digitalAccount(id)?.let { listOf(EnterpriseManageDao.run { it.toDigitalAccountItem() }) } + val item = EnterpriseManageDao.digitalAccount(id) + ?.let { EnterpriseManageDao.run { it.toDigitalAccountItem() } } + ?.takeIf { account.isNullOrBlank() || it.account.contains(account.trim(), ignoreCase = true) } + ?.takeIf { status.isNullOrBlank() || it.status == status.trim().uppercase() } + PageResult(listOfNotNull(item), page, pageSize, if (item == null) 0 else 1) + } + else -> PageResult(emptyList(), page, pageSize, 0) + } + } + + suspend fun listDigitalAccountOptions(user: CurrentUser, account: String?, limit: Int): List = dbQuery { + when { + user.isSuperAdmin || user.isEnterpriseAdmin -> { + EnterpriseManageDao.digitalAccountOptionsForEnterprise(requireEnterpriseId(user), account, limit.coerceIn(1, 200)) + } + user.isDigitalOperator -> { + val id = user.digitalAccountId + ?: throw BizException(ErrorCode.BAD_REQUEST.code, "当前账号未绑定数电账号") + EnterpriseManageDao.digitalAccount(id) + ?.let { EnterpriseManageDao.run { it.toDigitalAccountItem() } } + ?.takeIf { account.isNullOrBlank() || it.account.contains(account.trim(), ignoreCase = true) } + ?.let { listOf(it) } ?: emptyList() } else -> emptyList() @@ -97,7 +125,7 @@ object PTConfigService { ) } } - return listDigitalAccounts(user) + return listDigitalAccountOptions(user, null, 200) } suspend fun createDigitalAccount(user: CurrentUser, req: CreateDigitalAccountRequest): DigitalAccountManageItem { diff --git a/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/DatabaseInitializer.kt b/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/DatabaseInitializer.kt index e0e37b6..dd52409 100644 --- a/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/DatabaseInitializer.kt +++ b/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/DatabaseInitializer.kt @@ -59,6 +59,7 @@ object DatabaseInitializer { exec(it) } } + exec("ALTER TABLE open_invoice_task DROP COLUMN IF EXISTS run_mode") } logger.info("Database schema initialized") } diff --git a/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/Global.kt b/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/Global.kt index bea4805..0ad6d38 100644 --- a/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/Global.kt +++ b/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/Global.kt @@ -2,7 +2,7 @@ package com.bbit.ticket.utils.bootstrap object Global { - val isDev = true + val isDev = false // 请求基础地址 var baseUrl: String diff --git a/web/src/api/piaotong/index.ts b/web/src/api/piaotong/index.ts index 6b34832..ad73ccc 100644 --- a/web/src/api/piaotong/index.ts +++ b/web/src/api/piaotong/index.ts @@ -1,4 +1,4 @@ -import http from '@/api/http' +import http from '@/api/http' /** * 账号状态 @@ -158,8 +158,20 @@ export interface CreateDigitalAccountRequest { platformPassword: string } -export function listDigitalAccountsApi(): Promise { - return http.get('/pt/digital-accounts') +export function listDigitalAccountsApi(params: { + page: number + pageSize: number + account?: string | null + status?: string | null +}): Promise> { + return http.get('/pt/digital-accounts', { params }) +} + +export function digitalAccountOptionsApi(params?: { + account?: string | null + limit?: number +}): Promise { + return http.get('/pt/digital-accounts/options', { params }) } export function refreshDigitalAccountsApi(): Promise { @@ -244,7 +256,6 @@ export interface OpenInvoiceTaskItem { account?: string | null taskType: string sourceType: string - runMode: string invoiceReqSerialNo: string batchNo?: string | null status: string @@ -271,7 +282,6 @@ export function openInvoiceTaskPageApi(params: { digitalAccountId?: string status?: string | null sourceType?: string | null - runMode?: string | null }): Promise> { return http.get('/pt/openapi/tasks', { params }) } @@ -458,9 +468,9 @@ export function invoiceIssueApi(payload: InvoiceRequest): Promise { export interface RedCreateRequest { /** 蓝票历史记录 ID */ historyId: string - /** 平台数电账号 ID。企业管理员冲红时用于指定开票员 */ + /** 平台数电账号 ID。企业管理员红冲时用于指定开票员 */ digitalAccountId?: string | null - /** 冲红原因:01开票有误 02销货退回 03服务中止 04销售折让 */ + /** 红冲原因:01开票有误 02销货退回 03服务中止 04销售折让 */ redReason: string /** 收票人名称 */ takerName?: string @@ -577,7 +587,7 @@ export interface InvoiceHistoryItem { // ===== 发票状态标记 ===== /** 作废状态 */ invalidFlag?: string - /** 冲红状态 */ + /** 红冲状态 */ redFlag?: string // ===== 人员信息 ===== @@ -849,7 +859,7 @@ export function queryInvoiceApi( /** 红票申请信息 */ export interface RedInvoiceInfo { - /** 冲红原因:01开票有误 02销货退回 03服务中止 04销售折让 */ + /** 红冲原因:01开票有误 02销货退回 03服务中止 04销售折让 */ redReason: string /** 收票人名称 */ takerName?: string @@ -976,3 +986,4 @@ export function queryAuthStatusApi(payload: { }): Promise { return http.post('/pt/query-auth-status', payload) } + diff --git a/web/src/features/piaotong/digital-accounts/index.vue b/web/src/features/piaotong/digital-accounts/index.vue index abee72b..17819fa 100644 --- a/web/src/features/piaotong/digital-accounts/index.vue +++ b/web/src/features/piaotong/digital-accounts/index.vue @@ -4,6 +4,12 @@

数电账号管理

+ 刷新 @@ -22,9 +28,12 @@ :columns="columns" :data="accounts" :loading="loading" - :pagination="{ pageSize: 10 }" + :pagination="pagination" :row-key="(row: DigitalAccountItem) => row.id" :scroll-x="1460" + remote + @update:page="onPageChange" + @update:page-size="onPageSizeChange" />
@@ -133,8 +142,8 @@ + diff --git a/web/src/features/piaotong/invoice-issue/index.vue b/web/src/features/piaotong/invoice-issue/index.vue index 8b5839d..38c2fe8 100644 --- a/web/src/features/piaotong/invoice-issue/index.vue +++ b/web/src/features/piaotong/invoice-issue/index.vue @@ -931,7 +931,7 @@ import { invoiceIssueApi, getEnterpriseInfoApi, getPresetDataApi, - listDigitalAccountsApi + digitalAccountOptionsApi } from '@/api/piaotong' import type { DigitalAccountItem, InvoiceRequest, InvoiceItem, VariableLevyProof } from '@/api/piaotong' import type { FormInst, FormRules } from 'naive-ui' @@ -1574,7 +1574,7 @@ onMounted(async () => { const [enterpriseInfo, presetData, accounts] = await Promise.all([ getEnterpriseInfoApi(), getPresetDataApi(), - listDigitalAccountsApi() + digitalAccountOptionsApi({ limit: 200 }) ]) digitalAccounts.value = accounts const defaultAccount = diff --git a/web/src/features/statistics/openapi/index.vue b/web/src/features/statistics/openapi/index.vue index a03c649..745359d 100644 --- a/web/src/features/statistics/openapi/index.vue +++ b/web/src/features/statistics/openapi/index.vue @@ -66,15 +66,6 @@ class="task-filter" @update:value="loadTasks(1)" /> - 刷新 @@ -122,7 +113,6 @@ const taskPageSize = ref(20) const taskTotal = ref(0) const taskStatus = ref(null) const taskSourceType = ref(null) -const taskRunMode = ref(null) const statusOptions = [ { label: '待处理', value: 'PENDING' }, @@ -134,14 +124,35 @@ const statusOptions = [ const sourceTypeOptions = [ { label: '单笔', value: 'SINGLE' }, - { label: '批量', value: 'BATCH' }, - { label: '测试', value: 'TEST' } + { label: '批量', value: 'BATCH' } ] -const runModeOptions = [ - { label: '生产', value: 'REAL' }, - { label: '模拟', value: 'SIMULATED' } -] +const queueStatusLabelMap: Record = { + RUNNING: '运行中', + PAUSED: '已暂停' +} + +const taskStatusLabelMap: Record = { + PENDING: '待处理', + PROCESSING: '处理中', + SUCCESS: '成功', + FAILED: '失败', + WAITING_AUTH: '需认证' +} + +const taskTypeLabelMap: Record = { + ISSUE_BLUE: '蓝票开具', + QUERY_BLUE: '蓝票查询' +} + +const sourceTypeLabelMap: Record = { + SINGLE: '单笔', + BATCH: '批量' +} + +function labelOf(map: Record, value?: string | null) { + return value ? map[value] || value : '-' +} const totals = computed(() => rows.value.reduce( @@ -177,7 +188,11 @@ const columns: DataTableColumns = [ key: 'status', width: 110, render: (row) => - h(NTag, { type: statusTagType(row.status), size: 'small' }, { default: () => row.status }) + h( + NTag, + { type: statusTagType(row.status), size: 'small' }, + { default: () => labelOf(queueStatusLabelMap, row.status) } + ) }, { title: '待处理', key: 'pending', width: 90 }, { title: '处理中', key: 'processing', width: 90 }, @@ -265,15 +280,18 @@ function rowProps(row: OpenInvoiceTaskOverviewItem) { const taskColumns: DataTableColumns = [ { title: '票号', key: 'invoiceReqSerialNo', minWidth: 170 }, - { title: '任务', key: 'taskType', width: 120 }, - { title: '来源', key: 'sourceType', width: 90 }, - { title: '模式', key: 'runMode', width: 90 }, + { title: '任务', key: 'taskType', width: 120, render: (row) => labelOf(taskTypeLabelMap, row.taskType) }, + { title: '来源', key: 'sourceType', width: 90, render: (row) => labelOf(sourceTypeLabelMap, row.sourceType) }, { title: '状态', key: 'status', width: 110, render: (row) => - h(NTag, { type: statusTagType(row.status), size: 'small' }, { default: () => row.status }) + h( + NTag, + { type: statusTagType(row.status), size: 'small' }, + { default: () => labelOf(taskStatusLabelMap, row.status) } + ) }, { title: 'PT码', key: 'ptCode', width: 90 }, { title: '错误', key: 'errorMessage', minWidth: 260, ellipsis: { tooltip: true } }, @@ -307,7 +325,6 @@ async function loadTasks(page = 1) { digitalAccountId: selected.value.digitalAccountId, status: taskStatus.value, sourceType: taskSourceType.value, - runMode: taskRunMode.value, page, pageSize: taskPageSize.value }) @@ -326,7 +343,6 @@ function openDrawer(row: OpenInvoiceTaskOverviewItem) { drawerVisible.value = true taskStatus.value = null taskSourceType.value = null - taskRunMode.value = null loadTasks(1) }