diff --git a/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/BlueInvoiceDao.kt b/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/BlueInvoiceDao.kt index 08523c9..1219ea6 100644 --- a/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/BlueInvoiceDao.kt +++ b/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/BlueInvoiceDao.kt @@ -46,9 +46,9 @@ import kotlin.uuid.Uuid object BlueInvoiceDao { - fun listBatchNos(userId: Uuid): List = + fun listBatchNos(userId: Uuid, enterpriseId: Uuid?, digitalAccountId: Uuid?): List = OpenInvoiceBatchTable.selectAll() - .where { OpenInvoiceBatchTable.userId eq userId } + .where { batchScopeWhere(userId, enterpriseId, digitalAccountId) } .orderBy(OpenInvoiceBatchTable.createdAt, SortOrder.DESC) .map { it[OpenInvoiceBatchTable.batchNo] } @@ -69,14 +69,7 @@ object BlueInvoiceDao { isSuccess: Boolean? = null, batchNo: String? = null, ): PageResult { - val conditions = mutableListOf>() - if (digitalAccountId != null) { - conditions.add(HistoryInvoiceBasicTable.digitalAccountId eq digitalAccountId) - } else if (enterpriseId != null) { - conditions.add(HistoryInvoiceBasicTable.enterpriseId eq enterpriseId) - } else { - conditions.add(HistoryInvoiceBasicTable.userId eq userId) - } + val conditions = mutableListOf(invoiceScopeWhere(userId, enterpriseId, digitalAccountId)) conditions.add(HistoryInvoiceBasicTable.deletedAt.isNull()) // 发票类型筛选:前端传 BLUE/RED,库中存 1/2 @@ -105,7 +98,7 @@ object BlueInvoiceDao { val matchedSerialNos = (OpenInvoiceBatchItemTable innerJoin OpenInvoiceBatchTable) .selectAll() .where { - (OpenInvoiceBatchTable.userId eq userId) and + batchScopeWhere(userId, enterpriseId, digitalAccountId) and (OpenInvoiceBatchTable.batchNo like "%$normalizedBatchNo%") } .map { it[OpenInvoiceBatchItemTable.invoiceReqSerialNo] } @@ -138,7 +131,7 @@ object BlueInvoiceDao { (OpenInvoiceBatchItemTable innerJoin OpenInvoiceBatchTable) .selectAll() .where { - (OpenInvoiceBatchTable.userId eq userId) and + batchScopeWhere(userId, enterpriseId, digitalAccountId) and (OpenInvoiceBatchItemTable.invoiceReqSerialNo inList serialNos) } .associate { row -> @@ -451,18 +444,6 @@ object BlueInvoiceDao { it[HistoryInvoiceBasicTable.invDeletedFlag] = req.invDeletedFlag ?: "0" } - /** - * 根据流水号查询记录的 userId - */ - fun findUserIdBySerialNo(invoiceReqSerialNo: String): Uuid { - val row = HistoryInvoiceBasicTable.selectAll() - .where { HistoryInvoiceBasicTable.invoiceReqSerialNo eq invoiceReqSerialNo } - .singleOrNull() - ?: throw com.bbit.ticket.entity.common.BizException("NOT_FOUND", "发票记录不存在") - return row[HistoryInvoiceBasicTable.userId] - ?: throw com.bbit.ticket.entity.common.BizException("NOT_FOUND", "发票记录不存在用户信息") - } - fun findInvoiceScopeBySerialNo(invoiceReqSerialNo: String): InvoiceScope { val row = HistoryInvoiceBasicTable.selectAll() .where { HistoryInvoiceBasicTable.invoiceReqSerialNo eq invoiceReqSerialNo } @@ -528,10 +509,15 @@ object BlueInvoiceDao { .distinct() } - fun invoiceDownloadUrl(userId: Uuid, invoiceReqSerialNo: String): InvoiceDownloadUrlResponse? { + fun invoiceDownloadUrl( + userId: Uuid, + enterpriseId: Uuid?, + digitalAccountId: Uuid?, + invoiceReqSerialNo: String, + ): InvoiceDownloadUrlResponse? { val row = HistoryInvoiceBasicTable.selectAll() .where { - (HistoryInvoiceBasicTable.userId eq userId) and + invoiceScopeWhere(userId, enterpriseId, digitalAccountId) and (HistoryInvoiceBasicTable.invoiceReqSerialNo eq invoiceReqSerialNo) and HistoryInvoiceBasicTable.deletedAt.isNull() } @@ -543,14 +529,35 @@ object BlueInvoiceDao { /** * 查询发票完整详情(含商品明细、差额征税凭证、关联单据) */ - fun invoiceDetail(userId: Uuid, invoiceReqSerialNo: String): InvoiceDetailResponse? { + fun invoiceDetail( + userId: Uuid, + enterpriseId: Uuid?, + digitalAccountId: Uuid?, + invoiceReqSerialNo: String, + ): InvoiceDetailResponse? { val basicRow = HistoryInvoiceBasicTable.selectAll().where { - (HistoryInvoiceBasicTable.userId eq userId) and (HistoryInvoiceBasicTable.invoiceReqSerialNo eq invoiceReqSerialNo) + invoiceScopeWhere(userId, enterpriseId, digitalAccountId) and + (HistoryInvoiceBasicTable.invoiceReqSerialNo eq invoiceReqSerialNo) and + HistoryInvoiceBasicTable.deletedAt.isNull() }.singleOrNull() ?: return null return buildInvoiceDetailResponse(basicRow) } + private fun invoiceScopeWhere(userId: Uuid, enterpriseId: Uuid?, digitalAccountId: Uuid?): Op = + when { + digitalAccountId != null -> HistoryInvoiceBasicTable.digitalAccountId eq digitalAccountId + enterpriseId != null -> HistoryInvoiceBasicTable.enterpriseId eq enterpriseId + else -> HistoryInvoiceBasicTable.userId eq userId + } + + private fun batchScopeWhere(userId: Uuid, enterpriseId: Uuid?, digitalAccountId: Uuid?): Op = + when { + digitalAccountId != null -> OpenInvoiceBatchTable.digitalAccountId eq digitalAccountId + enterpriseId != null -> OpenInvoiceBatchTable.enterpriseId eq enterpriseId + else -> OpenInvoiceBatchTable.userId eq userId + } + /** * 根据主表行构建发票完整详情响应 */ 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 1fa0bad..f9bf13b 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 @@ -92,19 +92,19 @@ object EnterpriseManageDao { .where { (PtDigitalAccountTable.id eq id) and PtDigitalAccountTable.deletedAt.isNull() } .singleOrNull() - fun digitalAccountByApiKey(apiKey: String): ResultRow? = + fun digitalAccountByTaxpayerAndAccount(taxpayerNum: String, account: String): ResultRow? = PtDigitalAccountTable.selectAll() .where { - (PtDigitalAccountTable.apiKey eq apiKey) and - (PtDigitalAccountTable.status eq "ENABLED") and + (PtDigitalAccountTable.taxpayerNum eq taxpayerNum) and + (PtDigitalAccountTable.account eq account) and PtDigitalAccountTable.deletedAt.isNull() } .singleOrNull() - fun digitalAccountForUser(userId: Uuid): ResultRow? = + fun digitalAccountByApiKey(apiKey: String): ResultRow? = PtDigitalAccountTable.selectAll() .where { - (PtDigitalAccountTable.platformUserId eq userId) and + (PtDigitalAccountTable.apiKey eq apiKey) and (PtDigitalAccountTable.status eq "ENABLED") and PtDigitalAccountTable.deletedAt.isNull() } @@ -183,7 +183,6 @@ object EnterpriseManageDao { it[PtDigitalAccountTable.name] = name it[PtDigitalAccountTable.identityType] = identityType it[PtDigitalAccountTable.platformUserId] = platformUserId - it[PtDigitalAccountTable.apiKey] = apiKey it[updatedAt] = now } return id @@ -201,6 +200,13 @@ object EnterpriseManageDao { }[PtDigitalAccountTable.id] } + fun updateDigitalAccountStatus(digitalAccountId: Uuid, status: String) { + PtDigitalAccountTable.update({ PtDigitalAccountTable.id eq digitalAccountId }) { + it[PtDigitalAccountTable.status] = status + it[updatedAt] = OffsetDateTime.now() + } + } + fun bindDigitalAccountUser(digitalAccountId: Uuid, userId: Uuid) { PtDigitalAccountTable.update({ PtDigitalAccountTable.id eq digitalAccountId }) { it[platformUserId] = userId diff --git a/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/HistoryDao.kt b/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/HistoryDao.kt index 6c93494..58cc043 100644 --- a/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/HistoryDao.kt +++ b/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/HistoryDao.kt @@ -3,6 +3,7 @@ package com.bbit.ticket.dao.piaotong import com.bbit.ticket.database.piaotong.HistoryInvoiceBasicTable +import org.jetbrains.exposed.v1.core.Op import org.jetbrains.exposed.v1.core.and import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.v1.core.isNull @@ -41,14 +42,14 @@ object HistoryDao { /** * 根据历史记录 ID 查询蓝票基本信息 */ - fun findByHistory(historyId: Uuid?, userId: Uuid): HistoryRow { + fun findByHistory(historyId: Uuid?, userId: Uuid, enterpriseId: Uuid?, digitalAccountId: Uuid?): HistoryRow { if (historyId == null) { throw com.bbit.ticket.entity.common.BizException("NOT_FOUND", "历史记录 ID 为空") } val row = HistoryInvoiceBasicTable.selectAll() .where { (HistoryInvoiceBasicTable.id eq historyId) and - (HistoryInvoiceBasicTable.userId eq userId) and + scopeWhere(userId, enterpriseId, digitalAccountId) and HistoryInvoiceBasicTable.deletedAt.isNull() } .singleOrNull() @@ -79,4 +80,11 @@ object HistoryDao { ) } + private fun scopeWhere(userId: Uuid, enterpriseId: Uuid?, digitalAccountId: Uuid?): Op = + when { + digitalAccountId != null -> HistoryInvoiceBasicTable.digitalAccountId eq digitalAccountId + enterpriseId != null -> HistoryInvoiceBasicTable.enterpriseId eq enterpriseId + else -> HistoryInvoiceBasicTable.userId eq userId + } + } diff --git a/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/RedInvoiceDao.kt b/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/RedInvoiceDao.kt index f06ccb4..61c23c8 100644 --- a/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/RedInvoiceDao.kt +++ b/server/src/main/kotlin/com/bbit/ticket/dao/piaotong/RedInvoiceDao.kt @@ -7,6 +7,7 @@ import com.bbit.ticket.database.piaotong.HistoryInvoiceRedTable import com.bbit.ticket.entity.request.QuickRedInvoiceRequest import com.bbit.ticket.entity.response.InvoiceDownloadUrlResponse import com.bbit.ticket.entity.response.RedInvoiceInfoResponse +import org.jetbrains.exposed.v1.core.Op import org.jetbrains.exposed.v1.core.and import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.v1.core.isNull @@ -66,7 +67,7 @@ object RedInvoiceDao { it[HistoryInvoiceBasicTable.buyerBankAccount] = blueRow?.get(HistoryInvoiceBasicTable.buyerBankAccount) // ---- 金额 ---- - val redAmount = req.amount?.toBigDecimalOrNull() ?: BigDecimal.ZERO + val redAmount = req.amount.toBigDecimalOrNull() ?: BigDecimal.ZERO it[HistoryInvoiceBasicTable.noTaxAmount] = redAmount it[HistoryInvoiceBasicTable.taxAmount] = BigDecimal.ZERO it[HistoryInvoiceBasicTable.amountWithTax] = redAmount @@ -89,7 +90,7 @@ object RedInvoiceDao { it[HistoryInvoiceRedTable.historyId] = historyId it[HistoryInvoiceRedTable.invoiceReqSerialNo] = req.invoiceReqSerialNo it[HistoryInvoiceRedTable.redReason] = req.redReason - it[HistoryInvoiceRedTable.amount] = req.amount?.toBigDecimalOrNull() + it[HistoryInvoiceRedTable.amount] = req.amount.toBigDecimalOrNull() it[HistoryInvoiceRedTable.invoiceCode] = req.invoiceCode it[HistoryInvoiceRedTable.invoiceNo] = req.invoiceNo it[HistoryInvoiceRedTable.invoiceKind] = req.invoiceKind @@ -114,11 +115,24 @@ object RedInvoiceDao { /** * 根据流水号查询红票申请信息 */ - fun findRedInfoBySerialNo(userId: Uuid, invoiceReqSerialNo: String): RedInvoiceInfoResponse? { + fun findRedInfoBySerialNo( + userId: Uuid, + enterpriseId: Uuid?, + digitalAccountId: Uuid?, + invoiceReqSerialNo: String, + ): RedInvoiceInfoResponse? { + val canAccess = HistoryInvoiceBasicTable.selectAll() + .where { + scopeWhere(userId, enterpriseId, digitalAccountId) and + (HistoryInvoiceBasicTable.invoiceReqSerialNo eq invoiceReqSerialNo) and + HistoryInvoiceBasicTable.deletedAt.isNull() + } + .any() + if (!canAccess) return null + val row = HistoryInvoiceRedTable.selectAll() .where { - (HistoryInvoiceRedTable.userId eq userId) and - (HistoryInvoiceRedTable.invoiceReqSerialNo eq invoiceReqSerialNo) + HistoryInvoiceRedTable.invoiceReqSerialNo eq invoiceReqSerialNo } .singleOrNull() ?: return null @@ -130,10 +144,15 @@ object RedInvoiceDao { ) } - fun invoiceDownloadUrl(userId: Uuid, invoiceReqSerialNo: String): InvoiceDownloadUrlResponse? { + fun invoiceDownloadUrl( + userId: Uuid, + enterpriseId: Uuid?, + digitalAccountId: Uuid?, + invoiceReqSerialNo: String, + ): InvoiceDownloadUrlResponse? { val row = HistoryInvoiceBasicTable.selectAll() .where { - (HistoryInvoiceBasicTable.userId eq userId) and + scopeWhere(userId, enterpriseId, digitalAccountId) and (HistoryInvoiceBasicTable.invoiceReqSerialNo eq invoiceReqSerialNo) and (HistoryInvoiceBasicTable.invoiceType eq "2") and HistoryInvoiceBasicTable.deletedAt.isNull() @@ -142,4 +161,11 @@ object RedInvoiceDao { return InvoiceDownloadUrlResponse(row[HistoryInvoiceBasicTable.downloadUrl]) } + + private fun scopeWhere(userId: Uuid, enterpriseId: Uuid?, digitalAccountId: Uuid?): Op = + when { + digitalAccountId != null -> HistoryInvoiceBasicTable.digitalAccountId eq digitalAccountId + enterpriseId != null -> HistoryInvoiceBasicTable.enterpriseId eq enterpriseId + else -> HistoryInvoiceBasicTable.userId eq userId + } } diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/request/EnterpriseRegisterRequest.kt b/server/src/main/kotlin/com/bbit/ticket/entity/request/EnterpriseRegisterRequest.kt index 89fd25d..4fde2ed 100644 --- a/server/src/main/kotlin/com/bbit/ticket/entity/request/EnterpriseRegisterRequest.kt +++ b/server/src/main/kotlin/com/bbit/ticket/entity/request/EnterpriseRegisterRequest.kt @@ -49,3 +49,8 @@ data class UpdateInvoiceSettingRequest( val address: String = "", val phone: String = "", ) + +@Serializable +data class UpdateDigitalAccountStatusRequest( + val status: String, +) diff --git a/server/src/main/kotlin/com/bbit/ticket/entity/request/InvoiceQueryRequest.kt b/server/src/main/kotlin/com/bbit/ticket/entity/request/InvoiceQueryRequest.kt new file mode 100644 index 0000000..dbb6082 --- /dev/null +++ b/server/src/main/kotlin/com/bbit/ticket/entity/request/InvoiceQueryRequest.kt @@ -0,0 +1,155 @@ +package com.bbit.ticket.entity.request + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * 发票数据获取请求参数 + * + * 用于查询企业开具/取得的发票信息 + */ +@Serializable +data class InvoiceQueryRequest( + + /** + * 纳税人识别号 + * + * 长度:15-20 + * 仅支持大写字母和数字 + */ + @SerialName("taxpayerNum") + val taxpayerNum: String, + + /** + * 查询类型 + * + * 1:开具发票 + * 2:取得发票 + */ + @SerialName("queryType") + val queryType: String, + + /** + * 发票来源 + * + * 0:全部 + * 1:增值税发票管理系统 + * 2:电子发票服务平台 + */ + @SerialName("invSource") + val invSource: String? = null, + + /** + * 发票种类代码 + * + * 81:电子发票(增值税专用发票) + * 82:电子发票(普通发票) + * 10:增值税电子普通发票 + * 08:增值税电子专用发票 + * 04:增值税普通发票 + * 01:增值税专用发票 + */ + @SerialName("invoiceKind") + val invoiceKind: String? = null, + + /** + * 发票状态 + * + * 空字符串:全部 + * 01:正常 + * 02:已作废 + * 03:已红冲-全额 + * 04:已红冲-部分 + */ + @SerialName("invoiceState") + val invoiceState: String? = null, + + /** + * 数电号码 + * + * 查询数电发票时必填 + * 与 invoiceCode 至少传一个 + */ + @SerialName("electronicInvoiceNo") + val electronicInvoiceNo: String? = null, + + /** + * 发票代码 + * + * 长度:10 或 12 + * 查询税控系统发票时必填 + */ + @SerialName("invoiceCode") + val invoiceCode: String? = null, + + /** + * 发票号码 + * + * 长度:8 + * 查询税控系统发票时必填 + */ + @SerialName("invoiceNo") + val invoiceNo: String? = null, + + /** + * 开票日期 + * + * 格式:yyyyMMdd + * 示例:20221123 + */ + @SerialName("invoiceDate") + val invoiceDate: String, + + /** + * 对方纳税人税号 + */ + @SerialName("reciprocalTaxpayerNum") + val reciprocalTaxpayerNum: String? = null, + + /** + * 对方纳税人名称 + * + * 长度:4-100 + */ + @SerialName("reciprocalTaxpayerName") + val reciprocalTaxpayerName: String? = null, + + /** + * 电子税局登录账号 + */ + @SerialName("account") + val account: String? = null +) + +@Serializable +data class InvoiceQuerySubmitRequest( + @SerialName("digitalAccountId") + val digitalAccountId: String? = null, + + @SerialName("queryType") + val queryType: String, + + @SerialName("invSource") + val invSource: String? = null, + + @SerialName("invoiceKind") + val invoiceKind: String? = null, + + @SerialName("invoiceState") + val invoiceState: String? = null, + + @SerialName("electronicInvoiceNo") + val electronicInvoiceNo: String? = null, + + @SerialName("invoiceCode") + val invoiceCode: String? = null, + + @SerialName("invoiceDate") + val invoiceDate: String, + + @SerialName("reciprocalTaxpayerNum") + val reciprocalTaxpayerNum: String? = null, + + @SerialName("reciprocalTaxpayerName") + val reciprocalTaxpayerName: 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 new file mode 100644 index 0000000..f71691f --- /dev/null +++ b/server/src/main/kotlin/com/bbit/ticket/entity/response/InvoiceQueryResponse.kt @@ -0,0 +1,348 @@ +package com.bbit.ticket.entity.response + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * 发票数据获取响应报文 + */ +@Serializable +data class InvoiceQueryResponse( + + /** + * 获取结果代码 + * + * 0000:获取成功 + * 其他:获取失败,失败原因见 resultMsg + */ + @SerialName("resultCode") + val resultCode: String, + + /** + * 获取结果描述 + * + * 成功或失败时返回的说明信息 + */ + @SerialName("resultMsg") + val resultMsg: String? = null, + + /** + * 发票列表 + * + * 兼容后续批量查询场景 + */ + @SerialName("invoiceList") + val invoiceList: List = emptyList() +) + +/** + * 发票信息 + */ +@Serializable +data class InvoiceInfo( + + /** + * 购买方名称 + */ + @SerialName("buyerName") + val buyerName: String, + + /** + * 购买方纳税人识别号 + */ + @SerialName("buyerTaxpayerNum") + val buyerTaxpayerNum: String? = null, + + /** + * 购买方地址电话 + */ + @SerialName("buyerAddress") + val buyerAddress: String? = null, + + /** + * 购买方开户行及账号 + */ + @SerialName("buyerBankName") + val buyerBankName: String? = null, + + /** + * 销售方纳税人识别号 + */ + @SerialName("sellerTaxpayerNum") + val sellerTaxpayerNum: String, + + /** + * 销售方名称 + */ + @SerialName("sellerName") + val sellerName: String, + + /** + * 销售方地址电话 + */ + @SerialName("sellerAddress") + val sellerAddress: String? = null, + + /** + * 销售方开户行及账号 + */ + @SerialName("sellerBankName") + val sellerBankName: String? = null, + + /** + * 发票种类代码 + * + * 81:电子发票(增值税专用发票) + * 82:电子发票(普通发票) + * 10:增值税电子普通发票 + * 08:增值税电子专用发票 + * 04:增值税普通发票 + * 01:增值税专用发票 + */ + @SerialName("invoiceKind") + val invoiceKind: String, + + /** + * 开票日期 + * + * 格式:yyyy-MM-dd HH:mm:ss + */ + @SerialName("invoiceDate") + val invoiceDate: String, + + /** + * 发票代码 + * + * 税控系统发票可能返回 + */ + @SerialName("invoiceCode") + val invoiceCode: String? = null, + + /** + * 发票号码 + * + * 税控系统发票可能返回 + */ + @SerialName("invoiceNo") + val invoiceNo: String? = null, + + /** + * 数电发票号码 + */ + @SerialName("electronicInvoiceNo") + val electronicInvoiceNo: String? = null, + + /** + * 不含税金额 + * + * 保留小数点后 2 位 + */ + @SerialName("noTaxAmount") + val noTaxAmount: String, + + /** + * 税额 + * + * 保留小数点后 2 位 + */ + @SerialName("taxAmount") + val taxAmount: String, + + /** + * 价税合计 + * + * 保留小数点后 2 位 + */ + @SerialName("amountWithTax") + val amountWithTax: String, + + /** + * 作废标志 + * + * NOT_DESTROY:未作废 + * ALREADY_DESTROY:已作废 + * DESTROYING:作废中 + * DESTROY_FAIL:作废失败 + */ + @SerialName("invalidFlag") + val invalidFlag: String, + + /** + * 冲红标志 + * + * NOT_RED:未冲红 + * ALREADY_RED:已冲红 + * REDING:冲红中 + * RED_FAIL:冲红失败 + * PART_RED:部分冲红 + */ + @SerialName("redFlag") + val redFlag: String, + + /** + * 开票人名称 + */ + @SerialName("drawerName") + val drawerName: String, + + /** + * 收款人 + */ + @SerialName("casherName") + val casherName: String? = null, + + /** + * 复核人 + */ + @SerialName("reviewerName") + val reviewerName: String? = null, + + /** + * 备注 + * + * 数电发票一般限制 200 字符 + * 税控发票按 GBK 字节长度限制 240 字节 + */ + @SerialName("remark") + val remark: String? = null, + + /** + * 项目明细列表 + */ + @SerialName("itemList") + val itemList: List = emptyList() +) + +/** + * 发票项目明细 + */ +@Serializable +data class InvoiceItem( + + /** + * 货物或服务名称 + */ + @SerialName("goodsName") + val goodsName: String, + + /** + * 税收分类编码 + */ + @SerialName("taxClassificationCode") + val taxClassificationCode: String, + + /** + * 规格型号 + */ + @SerialName("specificationModel") + val specificationModel: String? = null, + + /** + * 单位 + */ + @SerialName("meteringUnit") + val meteringUnit: String? = null, + + /** + * 数量 + * + * 保留小数点后 8 位 + */ + @SerialName("quantity") + val quantity: String? = null, + + /** + * 单价 + * + * 保留小数点后 8 位 + */ + @SerialName("unitPrice") + val unitPrice: String? = null, + + /** + * 含税标识 + * + * 0:不含税 + * 1:含税 + */ + @SerialName("taxIncludeFlag") + val taxIncludeFlag: String, + + /** + * 项目金额 + * + * 保留小数点后 2 位 + */ + @SerialName("itemAmount") + val itemAmount: String, + + /** + * 税率 + * + * 保留小数点后 2 位,例如 0.13 + */ + @SerialName("taxRate") + val taxRate: String, + + /** + * 项目税额 + * + * 保留小数点后 2 位 + */ + @SerialName("taxRateAmount") + val taxRateAmount: String, + + /** + * 扣除额 + * + * 差额发票有值,保留小数点后 2 位 + */ + @SerialName("deduction") + val deduction: String? = null, + + /** + * 优惠政策标识 + * + * 0:不使用 + * 1:使用 + */ + @SerialName("preferentialPolicyFlag") + val preferentialPolicyFlag: String? = null, + + /** + * 零税率标识 + * + * 空:非零税率 + * 1:免税 + * 2:不征税 + * 3:普通零税率 + */ + @SerialName("zeroTaxFlag") + val zeroTaxFlag: String? = null, + + /** + * 增值税特殊管理 + * + * 例如:免税、不征税、简易征收等 + */ + @SerialName("vatSpecialManage") + val vatSpecialManage: String? = null, + + /** + * 发票行性质 + * + * 0:正常行 + * 1:折扣行 + * 2:被折扣行 + */ + @SerialName("itemProperty") + val itemProperty: String, + + /** + * 项目序号 + * + * 用于表示项目明细的先后顺序 + */ + @SerialName("itemNo") + val itemNo: String +) \ No newline at end of file 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 d02e0e0..fa1aa04 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 @@ -8,6 +8,7 @@ import com.bbit.ticket.entity.request.GetLoginSmsCodeRequest import com.bbit.ticket.entity.request.QueryRealNameAuthQrStatusRequest import com.bbit.ticket.entity.request.SmsLoginRequest import com.bbit.ticket.entity.request.TaxBureauAuthReq +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 @@ -73,6 +74,17 @@ fun Route.registerPTAuthRoutes() { } } + put("/digital-accounts/{id}/status") { + call.respondPt("更新数电账号状态失败") { + val id = call.parameters["id"] ?: throw IllegalArgumentException("缺少数电账号ID") + PTConfigService.updateDigitalAccountStatus( + call.requireCurrentUser(), + id, + call.receive(), + ) + } + } + get("/preset") { call.respondPtOrEmptyObject("查询预设数据失败") { PTConfigService.getEnterpriseInfo(call.requireCurrentUser()) @@ -115,13 +127,17 @@ fun Route.registerPTAuthRoutes() { post("/send-sms-code") { call.respondPt("发送登录短信验证码失败") { - PTAuthService.sendLoginSmsCode(call.receive()) + val req = call.receive() + PTConfigService.requireDigitalAccountForLogin(call.requireCurrentUser(), req.taxpayerNum, req.account) + PTAuthService.sendLoginSmsCode(req) } } post("/sms-login") { call.respondPt("短信验证码登录失败") { - PTAuthService.smsLogin(call.receive()) + val req = call.receive() + PTConfigService.requireDigitalAccountForLogin(call.requireCurrentUser(), req.taxpayerNum, req.account) + PTAuthService.smsLogin(req) } } } diff --git a/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerPTInvoiceRoutes.kt b/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerPTInvoiceRoutes.kt index 6733cab..28b2c22 100644 --- a/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerPTInvoiceRoutes.kt +++ b/server/src/main/kotlin/com/bbit/ticket/route/piaotong/registerPTInvoiceRoutes.kt @@ -4,6 +4,7 @@ package com.bbit.ticket.route.piaotong import com.bbit.ticket.entity.common.BizException import com.bbit.ticket.entity.request.AskInvoiceRequest +import com.bbit.ticket.entity.request.InvoiceQuerySubmitRequest import com.bbit.ticket.entity.request.QueryInvoiceRequest import com.bbit.ticket.entity.request.RedCreateRequest import com.bbit.ticket.service.piaotong.PTBlueService @@ -57,7 +58,7 @@ fun Route.registerPTInvoiceRoutes() { val invoiceReqSerialNo = call.requiredQueryParameter("invoiceReqSerialNo", "请传入发票请求流水号") ?: return@get call.respondPt("查询发票详情失败") { - PTBlueService.getInvoiceDetail(call.requireCurrentUser().id, invoiceReqSerialNo) + PTBlueService.getInvoiceDetail(call.requireCurrentUser(), invoiceReqSerialNo) ?: throw BizException("-1", "未找到该发票记录") } } @@ -66,7 +67,7 @@ fun Route.registerPTInvoiceRoutes() { val invoiceReqSerialNo = call.requiredQueryParameter("invoiceReqSerialNo", "请传入发票请求流水号") ?: return@get call.respondPt("查询发票下载地址失败") { - PTBlueService.getInvoiceDownloadUrl(call.requireCurrentUser().id, invoiceReqSerialNo) + PTBlueService.getInvoiceDownloadUrl(call.requireCurrentUser(), invoiceReqSerialNo) ?: throw BizException("-1", "未找到该发票记录") } } @@ -75,7 +76,7 @@ fun Route.registerPTInvoiceRoutes() { val invoiceReqSerialNo = call.requiredQueryParameter("invoiceReqSerialNo", "请传入发票请求流水号") ?: return@get call.respondPtPdf("预览票样失败", "$invoiceReqSerialNo.pdf") { - PTBlueService.getInvoicePreview(call.requireCurrentUser().id, invoiceReqSerialNo) + PTBlueService.getInvoicePreview(call.requireCurrentUser(), invoiceReqSerialNo) ?: throw BizException("-1", "未找到票样地址") } } @@ -84,7 +85,7 @@ fun Route.registerPTInvoiceRoutes() { val invoiceReqSerialNo = call.requiredQueryParameter("invoiceReqSerialNo", "请传入发票请求流水号") ?: return@get call.respondPt("查询红票下载地址失败") { - PTRedService.getRedInvoiceDownloadUrl(call.requireCurrentUser().id, invoiceReqSerialNo) + PTRedService.getRedInvoiceDownloadUrl(call.requireCurrentUser(), invoiceReqSerialNo) ?: throw BizException("-1", "未找到该红票记录") } } @@ -93,7 +94,7 @@ fun Route.registerPTInvoiceRoutes() { val invoiceReqSerialNo = call.requiredQueryParameter("invoiceReqSerialNo", "请传入发票请求流水号") ?: return@get call.respondPtPdf("预览红票票样失败", "$invoiceReqSerialNo.pdf") { - PTRedService.getRedInvoicePreview(call.requireCurrentUser().id, invoiceReqSerialNo) + PTRedService.getRedInvoicePreview(call.requireCurrentUser(), invoiceReqSerialNo) ?: throw BizException("-1", "未找到票样地址") } } @@ -120,7 +121,7 @@ fun Route.registerPTInvoiceRoutes() { val invoiceReqSerialNo = call.requiredQueryParameter("invoiceReqSerialNo", "请传入发票请求流水号") ?: return@get call.respondPt("查询红票申请信息失败") { - PTRedService.getRedInvoiceInfo(call.requireCurrentUser().id, invoiceReqSerialNo) + PTRedService.getRedInvoiceInfo(call.requireCurrentUser(), invoiceReqSerialNo) ?: throw BizException("-1", "未找到红票申请信息") } } diff --git a/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTAuthService.kt b/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTAuthService.kt index 5c14dfd..2621aaa 100644 --- a/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTAuthService.kt +++ b/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTAuthService.kt @@ -13,86 +13,45 @@ import com.bbit.ticket.entity.request.TaxBureauAuthReq import com.bbit.ticket.entity.response.AuthQrcodeResponse import com.bbit.ticket.entity.response.AuthQrcodeStatusResponse import com.bbit.ticket.entity.response.DigitalAccountInfo -import com.bbit.ticket.entity.response.EnterpriseTaxInfo import com.bbit.ticket.entity.response.LoginSmsCodeResponse import com.bbit.ticket.entity.response.QueryEnterpriseBankAccountResponse import com.bbit.ticket.entity.response.QueryEnterpriseInfoResponse import com.bbit.ticket.entity.response.SMSLoginResponse import com.bbit.ticket.entity.response.TaxBureauAccountAuthContent -import com.bbit.ticket.utils.net.PTClient +import com.bbit.ticket.utils.net.PTApi object PTAuthService { - /** - * 查询数电账号认证状态 2.8 - */ suspend fun getTaxBureauAccountAuthStatus(req: TaxBureauAuthReq): TaxBureauAccountAuthContent { - val res = - PTClient.ptPost("getTaxBureauAccountAuthStatus.pt", req) - return res + return PTApi.getTaxBureauAccountAuthStatus(req) } - /** - * 获取实名认证二维码 2.6 - * - * @return AuthQrcodeResponse 包含 base64 二维码图片 - */ suspend fun getAuthenticationQrcode(req: AuthQrcodeRequest): AuthQrcodeResponse { - return PTClient.ptPost("getAuthenticationQrcode.pt", req) + return PTApi.getAuthenticationQrcode(req) } - /** - * 查询认证二维码扫码状态 2.7 - * - * @return AuthQrcodeStatusResponse 包含 scanStatus、msg - */ suspend fun queryAuthQrcodeScanStatus(req: QueryRealNameAuthQrStatusRequest): AuthQrcodeStatusResponse { - return PTClient.ptPost( - "queryAuthQrcodeScanStatus.pt", - req - ) + return PTApi.queryAuthQrcodeScanStatus(req) } - /** - * 发送登录短信验证码 2.4 - * - * @return LoginSmsCodeResponse 包含脱敏手机号、有效时长 - */ suspend fun sendLoginSmsCode(req: GetLoginSmsCodeRequest): LoginSmsCodeResponse { - return PTClient.ptPost("sendLoginSmsCode.pt", req) + return PTApi.sendLoginSmsCode(req) } - /** - * 短信验证码登录 2.5 - * - * @return SMSLoginResponse 包含登录结果 - */ suspend fun smsLogin(req: SmsLoginRequest): SMSLoginResponse { - return PTClient.ptPost("smsLogin.pt", req) + return PTApi.smsLogin(req) } - /** - * 查询企业状态 2.47 - */ suspend fun getEnterpriseInfo(req: QueryEnterpriseInfoRequest): QueryEnterpriseInfoResponse { - return PTClient.ptPost("getEnterpriseInfo.pt", req) + return PTApi.getEnterpriseInfo(req) } - /** - * 查询数电账号列表 2.45 - */ suspend fun getListTaxBureauAccount(req: QueryDigitalAccountListRequest): List { - return PTClient.ptPost>( - "listTaxBureauAccount.pt", - req - ) + return PTApi.listTaxBureauAccount(req) } - /** - * 查询企业开户行及账号 2.49 - */ suspend fun queryEnterpriseBankInfo(req: QueryEnterpriseBankAccountRequest): QueryEnterpriseBankAccountResponse { - return PTClient.ptPost("queryEnterpriseBankInfo.pt", req) + return PTApi.queryEnterpriseBankInfo(req) } } diff --git a/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTBlueService.kt b/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTBlueService.kt index 2af8135..ae94bda 100644 --- a/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTBlueService.kt +++ b/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTBlueService.kt @@ -5,17 +5,19 @@ package com.bbit.ticket.service.piaotong import com.bbit.ticket.dao.piaotong.BlueInvoiceDao import com.bbit.ticket.entity.common.PageResult import com.bbit.ticket.entity.request.AskInvoiceRequest +import com.bbit.ticket.entity.request.InvoiceQueryRequest +import com.bbit.ticket.entity.request.InvoiceQuerySubmitRequest import com.bbit.ticket.entity.request.QueryInvoiceRequest -import com.bbit.ticket.entity.response.GetInvoiceInfoResponse import com.bbit.ticket.entity.response.InvoiceDownloadUrlResponse import com.bbit.ticket.entity.response.QueryInvoiceResult -import com.bbit.ticket.entity.response.InvoiceCreateResponse import com.bbit.ticket.entity.response.InvoiceDetailResponse import com.bbit.ticket.entity.response.InvoiceHistoryItem +import com.bbit.ticket.entity.response.InvoiceQueryResponse import com.bbit.ticket.utils.CurrentUser import io.ktor.client.request.get import io.ktor.client.statement.bodyAsBytes import com.bbit.ticket.utils.plugins.dbQuery +import com.bbit.ticket.utils.net.PTApi import com.bbit.ticket.utils.net.PTClient import com.bbit.ticket.utils.parseUuid import kotlin.uuid.Uuid @@ -23,7 +25,13 @@ import kotlin.uuid.Uuid object PTBlueService { suspend fun listBatchNos(user: CurrentUser): List = - dbQuery { BlueInvoiceDao.listBatchNos(user.id) } + dbQuery { + BlueInvoiceDao.listBatchNos( + user.id, + user.enterpriseId, + if (user.isDigitalOperator) user.digitalAccountId else null, + ) + } /** * 查询票通同步发票信息(支持插入和更新) @@ -38,8 +46,7 @@ object PTBlueService { enterpriseId: Uuid? = null, digitalAccountId: Uuid? = null, ): QueryInvoiceResult { - val res = PTClient.ptPost( - "queryInvoiceInfo.pt", + val res = PTApi.queryInvoiceInfo( QueryInvoiceRequest(taxpayerNum = taxpayerNum, invoiceReqSerialNo = invoiceReqSerialNo) ) dbQuery { BlueInvoiceDao.upsertInvoiceInfo(userId, res, enterpriseId, digitalAccountId) } @@ -77,7 +84,7 @@ object PTBlueService { ): String { dbQuery { BlueInvoiceDao.addInvoice(userId, req, enterpriseId, digitalAccountId) } try { - PTClient.ptPost("invoiceBlue.pt", req) + PTApi.invoiceBlue(req) } catch (e: Exception) { dbQuery { BlueInvoiceDao.markInvoiceFailed(userId, req.invoiceReqSerialNo, e.message) } throw e @@ -89,9 +96,6 @@ object PTBlueService { return "操作成功" } - /** - * 分页查询开票历史(支持筛选) - */ suspend fun getInvoiceBlueHistory( user: CurrentUser, page: Int, @@ -117,10 +121,30 @@ object PTBlueService { * 查询发票完整详情 */ suspend fun getInvoiceDetail(userId: Uuid, invoiceReqSerialNo: String): InvoiceDetailResponse? = - dbQuery { BlueInvoiceDao.invoiceDetail(userId, invoiceReqSerialNo) } + dbQuery { BlueInvoiceDao.invoiceDetail(userId, null, null, invoiceReqSerialNo) } + + suspend fun getInvoiceDetail(user: CurrentUser, invoiceReqSerialNo: String): InvoiceDetailResponse? = + dbQuery { + BlueInvoiceDao.invoiceDetail( + user.id, + user.enterpriseId, + if (user.isDigitalOperator) user.digitalAccountId else null, + invoiceReqSerialNo, + ) + } suspend fun getInvoiceDownloadUrl(userId: Uuid, invoiceReqSerialNo: String): InvoiceDownloadUrlResponse? = - dbQuery { BlueInvoiceDao.invoiceDownloadUrl(userId, invoiceReqSerialNo) } + dbQuery { BlueInvoiceDao.invoiceDownloadUrl(userId, null, null, invoiceReqSerialNo) } + + suspend fun getInvoiceDownloadUrl(user: CurrentUser, invoiceReqSerialNo: String): InvoiceDownloadUrlResponse? = + dbQuery { + BlueInvoiceDao.invoiceDownloadUrl( + user.id, + user.enterpriseId, + if (user.isDigitalOperator) user.digitalAccountId else null, + invoiceReqSerialNo, + ) + } suspend fun getInvoicePreview(userId: Uuid, invoiceReqSerialNo: String): ByteArray? { val downloadUrl = getInvoiceDownloadUrl(userId, invoiceReqSerialNo)?.downloadUrl @@ -129,6 +153,13 @@ object PTBlueService { return PTClient.client.get(downloadUrl).bodyAsBytes() } + suspend fun getInvoicePreview(user: CurrentUser, invoiceReqSerialNo: String): ByteArray? { + val downloadUrl = getInvoiceDownloadUrl(user, invoiceReqSerialNo)?.downloadUrl + ?.takeIf { it.isNotBlank() } + ?: return null + return PTClient.client.get(downloadUrl).bodyAsBytes() + } + /** * 查询并更新发票状态(复用 syncInvoiceFromPT) */ 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 e51b698..d6511a5 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 @@ -11,12 +11,12 @@ import com.bbit.ticket.entity.request.QueryDigitalAccountListRequest import com.bbit.ticket.entity.request.QueryEnterpriseBankAccountRequest import com.bbit.ticket.entity.request.QueryEnterpriseInfoRequest import com.bbit.ticket.entity.request.TaxRegister +import com.bbit.ticket.entity.request.UpdateDigitalAccountStatusRequest import com.bbit.ticket.entity.request.UpdateInvoiceSettingRequest import com.bbit.ticket.entity.response.BankInfo import com.bbit.ticket.entity.response.DigitalAccountInfo import com.bbit.ticket.entity.response.DigitalAccountManageItem import com.bbit.ticket.entity.response.EnterpriseManageResponse -import com.bbit.ticket.entity.response.EtaxRegisterResponse import com.bbit.ticket.entity.response.OpenApiStatisticsItem import com.bbit.ticket.utils.plugins.dbQuery import com.bbit.ticket.entity.common.BizException @@ -24,7 +24,7 @@ import com.bbit.ticket.entity.common.ErrorCode import com.bbit.ticket.service.system.PasswordService import com.bbit.ticket.utils.ApiKeyUtil import com.bbit.ticket.utils.CurrentUser -import com.bbit.ticket.utils.net.PTClient +import com.bbit.ticket.utils.net.PTApi import com.bbit.ticket.utils.parseUuid import io.ktor.http.HttpStatusCode import kotlin.uuid.Uuid @@ -109,8 +109,7 @@ object PTConfigService { ?: throw BizException(ErrorCode.BAD_REQUEST.code, "企业信息不存在", HttpStatusCode.BadRequest) } - PTClient.ptPost( - "registerUser.pt", + PTApi.registerDigitalAccount( TaxRegister( taxpayerNum = enterprise.taxpayerNum, account = req.account, @@ -147,6 +146,28 @@ object PTConfigService { } } + suspend fun updateDigitalAccountStatus( + user: CurrentUser, + digitalAccountId: String, + req: UpdateDigitalAccountStatusRequest, + ): String = dbQuery { + if (!user.isSuperAdmin && !user.isEnterpriseAdmin) { + throw BizException(ErrorCode.FORBIDDEN.code, "无权操作数电账号", HttpStatusCode.Forbidden) + } + val status = req.status.trim().uppercase() + if (status !in setOf("ENABLED", "DISABLED")) { + throw BizException(ErrorCode.BAD_REQUEST.code, "账号状态必须是 ENABLED 或 DISABLED") + } + val targetId = parseUuid(digitalAccountId, "digitalAccountId") + val row = EnterpriseManageDao.digitalAccount(targetId) + ?: throw BizException(ErrorCode.BAD_REQUEST.code, "数电账号不存在", HttpStatusCode.NotFound) + if (row[PtDigitalAccountTable.enterpriseId] != requireEnterpriseId(user)) { + throw BizException(ErrorCode.FORBIDDEN.code, "无权操作该数电账号", HttpStatusCode.Forbidden) + } + EnterpriseManageDao.updateDigitalAccountStatus(targetId, status) + if (status == "ENABLED") "数电账号已恢复" else "数电账号已禁用" + } + private fun ensureDigitalOperatorAccount( enterpriseId: Uuid, taxpayerNum: String, @@ -220,6 +241,22 @@ object PTConfigService { if (!user.isSuperAdmin && row[PtDigitalAccountTable.enterpriseId] != requireEnterpriseId(user)) { throw BizException(ErrorCode.FORBIDDEN.code, "无权操作该数电账号", HttpStatusCode.Forbidden) } + if (row[PtDigitalAccountTable.status] != "ENABLED") { + throw BizException(ErrorCode.FORBIDDEN.code, "数电账号已禁用", HttpStatusCode.Forbidden) + } EnterpriseManageDao.run { row.toDigitalAccountItem() } } + + suspend fun requireDigitalAccountForLogin(user: CurrentUser, taxpayerNum: String, account: String): DigitalAccountManageItem = + dbQuery { + val row = EnterpriseManageDao.digitalAccountByTaxpayerAndAccount(taxpayerNum.trim(), account.trim()) + ?: throw BizException(ErrorCode.BAD_REQUEST.code, "数电账号不存在", HttpStatusCode.NotFound) + if (!user.isSuperAdmin && row[PtDigitalAccountTable.enterpriseId] != requireEnterpriseId(user)) { + throw BizException(ErrorCode.FORBIDDEN.code, "无权操作该数电账号", HttpStatusCode.Forbidden) + } + if (row[PtDigitalAccountTable.status] != "ENABLED") { + throw BizException(ErrorCode.FORBIDDEN.code, "数电账号已禁用", HttpStatusCode.Forbidden) + } + EnterpriseManageDao.run { row.toDigitalAccountItem() } + } } diff --git a/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTRedService.kt b/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTRedService.kt index d21c446..4684d4f 100644 --- a/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTRedService.kt +++ b/server/src/main/kotlin/com/bbit/ticket/service/piaotong/PTRedService.kt @@ -7,10 +7,10 @@ import com.bbit.ticket.dao.piaotong.RedInvoiceDao import com.bbit.ticket.entity.request.QuickRedInvoiceRequest import com.bbit.ticket.entity.request.RedCreateRequest import com.bbit.ticket.entity.response.InvoiceDownloadUrlResponse -import com.bbit.ticket.entity.response.QuickRedInvoiceResponse import com.bbit.ticket.entity.response.RedInvoiceInfoResponse import com.bbit.ticket.utils.CurrentUser import com.bbit.ticket.utils.plugins.dbQuery +import com.bbit.ticket.utils.net.PTApi import com.bbit.ticket.utils.net.PTClient import com.bbit.ticket.utils.parseUuid import io.ktor.client.request.get @@ -25,14 +25,19 @@ import kotlin.uuid.Uuid object PTRedService { /** - * 红票接口调用 + * 红票接口调用 2.10 */ - suspend fun invoiceRed(user: CurrentUser,req:RedCreateRequest): String { + suspend fun invoiceRed(user: CurrentUser, req: RedCreateRequest): String { val account = PTConfigService.requireDigitalAccountForAction(user, null) val invoiceReqSerialNo = PTClient.ptDate() val historyId = Uuid.parse(req.historyId) val his = dbQuery { - HistoryDao.findByHistory(historyId, user.id) + HistoryDao.findByHistory( + historyId, + user.id, + user.enterpriseId, + if (user.isDigitalOperator) user.digitalAccountId else null, + ) } val req = QuickRedInvoiceRequest( taxpayerNum = account.taxpayerNum, @@ -42,33 +47,57 @@ object PTRedService { blueAllEleInvNo = his.electronicInvoiceNo, blueInvoiceDate = his.blueInvoiceDate, redReason = req.redReason, - amount = his.totalAmount?.negate()?.toPlainString()?:"0.0", + amount = his.totalAmount?.negate()?.toPlainString() ?: "0.0", account = account.account, invoiceKind = his.invoiceKind, takerName = req.takerName, takerTel = req.takerTel, takerEmail = req.takerEmail, ) - PTClient.ptPost("invoiceRed.pt", req) + PTApi.invoiceRed(req) dbQuery { RedInvoiceDao.addRedInvoice(user.id, historyId, req) } val enterpriseId = parseUuid(account.enterpriseId, "enterpriseId") val digitalAccountId = parseUuid(account.id, "digitalAccountId") - PTBlueService.syncInvoiceFromPT(user.id, his.invoiceReqSerialNo, account.taxpayerNum, enterpriseId, digitalAccountId) - PTBlueService.syncInvoiceFromPT(user.id, invoiceReqSerialNo, account.taxpayerNum, enterpriseId, digitalAccountId) + PTBlueService.syncInvoiceFromPT( + user.id, + his.invoiceReqSerialNo, + account.taxpayerNum, + enterpriseId, + digitalAccountId + ) + PTBlueService.syncInvoiceFromPT( + user.id, + invoiceReqSerialNo, + account.taxpayerNum, + enterpriseId, + digitalAccountId + ) return "操作成功" } /** * 查询红票申请信息 */ - suspend fun getRedInvoiceInfo(userId: Uuid, invoiceReqSerialNo: String): RedInvoiceInfoResponse? = - dbQuery { RedInvoiceDao.findRedInfoBySerialNo(userId, invoiceReqSerialNo) } + suspend fun getRedInvoiceInfo(user: CurrentUser, invoiceReqSerialNo: String): RedInvoiceInfoResponse? = + dbQuery { + RedInvoiceDao.findRedInfoBySerialNo( + user.id, user.enterpriseId, if (user.isDigitalOperator) user.digitalAccountId else null, + invoiceReqSerialNo, + ) + } - suspend fun getRedInvoiceDownloadUrl(userId: Uuid, invoiceReqSerialNo: String): InvoiceDownloadUrlResponse? = - dbQuery { RedInvoiceDao.invoiceDownloadUrl(userId, invoiceReqSerialNo) } + suspend fun getRedInvoiceDownloadUrl(user: CurrentUser, invoiceReqSerialNo: String): InvoiceDownloadUrlResponse? = + dbQuery { + RedInvoiceDao.invoiceDownloadUrl( + user.id, + user.enterpriseId, + if (user.isDigitalOperator) user.digitalAccountId else null, + invoiceReqSerialNo, + ) + } - suspend fun getRedInvoicePreview(userId: Uuid, invoiceReqSerialNo: String): ByteArray? { - val downloadUrl = getRedInvoiceDownloadUrl(userId, invoiceReqSerialNo)?.downloadUrl + suspend fun getRedInvoicePreview(user: CurrentUser, invoiceReqSerialNo: String): ByteArray? { + val downloadUrl = getRedInvoiceDownloadUrl(user, invoiceReqSerialNo)?.downloadUrl ?.takeIf { it.isNotBlank() } ?: return null return PTClient.client.get(downloadUrl).bodyAsBytes() diff --git a/server/src/main/kotlin/com/bbit/ticket/service/system/AuthService.kt b/server/src/main/kotlin/com/bbit/ticket/service/system/AuthService.kt index f28e1be..1e1e45b 100644 --- a/server/src/main/kotlin/com/bbit/ticket/service/system/AuthService.kt +++ b/server/src/main/kotlin/com/bbit/ticket/service/system/AuthService.kt @@ -13,12 +13,10 @@ import com.bbit.ticket.entity.common.system.LoginRequest import com.bbit.ticket.entity.common.system.LoginResponse import com.bbit.ticket.entity.common.system.MeResponse import com.bbit.ticket.entity.request.EnterpriseRegisterRequest -import com.bbit.ticket.entity.request.TaxRegisterInfo import com.bbit.ticket.entity.request.toTaxRegisterInfo -import com.bbit.ticket.entity.response.EnterpriseTaxInfo import com.bbit.ticket.utils.plugins.dbQuery import com.bbit.ticket.utils.CurrentUser -import com.bbit.ticket.utils.net.PTClient +import com.bbit.ticket.utils.net.PTApi import io.ktor.http.HttpStatusCode import kotlin.uuid.ExperimentalUuidApi @@ -92,7 +90,7 @@ object AuthService { throw BizException(ErrorCode.DATA_CONFLICT.code, "企业已存在", HttpStatusCode.Conflict) } } - PTClient.ptPost("register.pt", registerInfo) + PTApi.registerEnterprise(registerInfo) dbQuery { val enterpriseId = EnterpriseManageDao.createEnterprise(registerInfo) 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 0ad6d38..bea4805 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 = false + val isDev = true // 请求基础地址 var baseUrl: String diff --git a/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/SeedData.kt b/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/SeedData.kt index 8f0c62d..0d202b7 100644 --- a/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/SeedData.kt +++ b/server/src/main/kotlin/com/bbit/ticket/utils/bootstrap/SeedData.kt @@ -2,9 +2,14 @@ package com.bbit.ticket.utils.bootstrap +import com.bbit.ticket.dao.piaotong.EnterpriseManageDao +import com.bbit.ticket.database.piaotong.PtEnterpriseTable import com.bbit.ticket.database.system.* -import com.bbit.ticket.utils.plugins.dbQuery +import com.bbit.ticket.entity.request.QueryEnterpriseInfoRequest +import com.bbit.ticket.entity.request.TaxRegisterInfo import com.bbit.ticket.service.system.PasswordService +import com.bbit.ticket.utils.net.PTApi +import com.bbit.ticket.utils.plugins.dbQuery import org.jetbrains.exposed.v1.core.and import org.jetbrains.exposed.v1.core.eq import org.jetbrains.exposed.v1.core.inList @@ -26,6 +31,7 @@ object SeedData { const val ADMIN_INIT_PASSWORD = "Admin@123456" private const val DEFAULT_ORG_CODE = "DEFAULT_ORG" + private const val DEFAULT_ADMIN_TAXPAYER_NUM = "500102201007206608" private const val SUPER_ADMIN_ROLE_CODE = "SUPER_ADMIN" private const val ENTERPRISE_ADMIN_ROLE_CODE = "ENTERPRISE_ADMIN" private const val DIGITAL_OPERATOR_ROLE_CODE = "DIGITAL_OPERATOR" @@ -38,6 +44,7 @@ object SeedData { val now = OffsetDateTime.now() val orgId = upsertDefaultOrg(now) val roleId = upsertSuperAdminRole(now) + val defaultEnterpriseId = ensureDefaultAdminEnterprise() val enterpriseAdminRoleId = upsertBusinessRole( code = ENTERPRISE_ADMIN_ROLE_CODE, name = "企业管理员", @@ -50,9 +57,10 @@ object SeedData { description = "数电账号对应的平台开票员角色", now = now, ) - val adminId = upsertAdminUser(orgId, now) + val adminId = upsertAdminUser(orgId, defaultEnterpriseId, now) upsertUserRole(adminId, roleId) val menuIds = upsertMenus(now) + disableObsoleteMenus(now) bindRoleMenus(roleId, menuIds.values.toList()) bindRoleMenus(enterpriseAdminRoleId, enterpriseAdminMenuIds(menuIds)) bindRoleMenus(digitalOperatorRoleId, digitalOperatorMenuIds(menuIds)) @@ -156,7 +164,40 @@ object SeedData { // Admin user // ========================================================= - private suspend fun upsertAdminUser(orgId: Uuid, now: OffsetDateTime): Uuid = dbQuery { + private suspend fun ensureDefaultAdminEnterprise(): Uuid { + val existingId = dbQuery { + EnterpriseManageDao.findEnterpriseByTaxpayerNum(DEFAULT_ADMIN_TAXPAYER_NUM)?.get(PtEnterpriseTable.id) + } + val ptEnterprise = PTApi.getEnterpriseInfo(QueryEnterpriseInfoRequest(DEFAULT_ADMIN_TAXPAYER_NUM)) + + if (existingId != null) { + dbQuery { EnterpriseManageDao.updateEnterpriseFromPt(existingId, ptEnterprise) } + return existingId + } + + val enterpriseInfo = TaxRegisterInfo( + taxpayerNum = DEFAULT_ADMIN_TAXPAYER_NUM, + enterpriseName = ptEnterprise.enterpriseName.ifBlank { DEFAULT_ADMIN_TAXPAYER_NUM }, + legalPersonName = null, + contactsName = null, + contactsEmail = null, + contactsPhone = null, + regionCode = ptEnterprise.regionCode, + cityName = ptEnterprise.cityName, + enterpriseAddress = ptEnterprise.enterpriseAddress, + taxRegistrationCertificate = null, + ) + + return dbQuery { + val enterpriseId = EnterpriseManageDao.findEnterpriseByTaxpayerNum(DEFAULT_ADMIN_TAXPAYER_NUM) + ?.get(PtEnterpriseTable.id) + ?: EnterpriseManageDao.createEnterprise(enterpriseInfo) + EnterpriseManageDao.updateEnterpriseFromPt(enterpriseId, ptEnterprise) + enterpriseId + } + } + + private suspend fun upsertAdminUser(orgId: Uuid, enterpriseId: Uuid, now: OffsetDateTime): Uuid = dbQuery { val existing = SysUserTable.selectAll() .where { (SysUserTable.username eq ADMIN_USERNAME) and SysUserTable.deletedAt.isNull() } .singleOrNull() @@ -166,6 +207,7 @@ object SeedData { SysUserTable.update({ SysUserTable.id eq id }) { it[SysUserTable.nickname] = "系统管理员" it[SysUserTable.orgId] = orgId + it[SysUserTable.enterpriseId] = enterpriseId it[SysUserTable.status] = "ENABLED" it[SysUserTable.userType] = "SYSTEM" it[SysUserTable.updatedAt] = now @@ -180,6 +222,7 @@ object SeedData { it[SysUserTable.passwordHash] = PasswordService.hash(ADMIN_INIT_PASSWORD) it[SysUserTable.nickname] = "系统管理员" it[SysUserTable.orgId] = orgId + it[SysUserTable.enterpriseId] = enterpriseId it[SysUserTable.status] = "ENABLED" it[SysUserTable.userType] = "SYSTEM" it[SysUserTable.tokenVersion] = 1 @@ -234,15 +277,15 @@ object SeedData { catalog("logs", "日志管理", "LogsRoot", "Logs", 30), subMenu("logs_operation", "logs", "操作日志", "LogsOperation", "/logs/operation", "logs/operation/index", "ScrollText", "log:operation:view", 10), subMenu("logs_api_access", "logs", "接口日志", "LogsApiAccess", "/logs/api-access", "logs/api-access/index", "Waypoints", "log:api-access:view", 20), + subMenu("openapi_statistics", "logs", "OpenAPI", "OpenApiStatistics", "/logs/openapi", "statistics/openapi/index", "Waypoints", "openapi:statistics:view", 30), catalog("basic_info", "基础信息", "BasicInfoRoot", "Building2", 40), subMenu("enterprise_info", "basic_info", "企业信息", "EnterpriseInfo", "/enterprise/info", "piaotong/index", "Building2", "enterprise:info:view", 10), subMenu("digital_account", "basic_info", "数电账号", "DigitalAccountManage", "/enterprise/digital-accounts", "piaotong/digital-accounts/index", "Users", "digital-account:view", 20), + button("digital_account_status", "digital_account", "禁用/恢复数电账号", "DigitalAccountStatus", "digital-account:status", 1), subMenu("invoice_setting", "basic_info", "开票设置", "InvoiceSetting", "/enterprise/invoice-setting", "piaotong/invoice-setting/index", "SlidersHorizontal", "invoice-setting:view", 30), catalog("invoice_service", "开票服务", "InvoiceServiceRoot", "Receipt", 50), subMenu("piaotong_invoice_issue", "invoice_service", "开具蓝票", "PiaoTongInvoiceIssue", "/piaotong/invoice-issue", "piaotong/invoice-issue/index", "FilePlus", "piaotong:invoice-issue:view", 10), subMenu("piaotong_invoice_history", "invoice_service", "开票历史", "PiaoTongInvoiceHistory", "/piaotong/invoice-history", "piaotong/invoice-history/index", "History", "piaotong:invoice-history:view", 20), - catalog("statistics_info", "统计信息", "StatisticsInfoRoot", "ChartNoAxesColumn", 60), - subMenu("openapi_statistics", "statistics_info", "OpenAPI", "OpenApiStatistics", "/statistics/openapi", "statistics/openapi/index", "Waypoints", "openapi:statistics:view", 10), ) val idMap = mutableMapOf() @@ -260,11 +303,11 @@ object SeedData { "basic_info", "enterprise_info", "digital_account", + "digital_account_status", "invoice_setting", "invoice_service", "piaotong_invoice_issue", "piaotong_invoice_history", - "statistics_info", "openapi_statistics", ).mapNotNull { menuIds[it] } @@ -276,7 +319,6 @@ object SeedData { "invoice_service", "piaotong_invoice_issue", "piaotong_invoice_history", - "statistics_info", "openapi_statistics", ).mapNotNull { menuIds[it] } @@ -351,6 +393,16 @@ object SeedData { } } + private suspend fun disableObsoleteMenus(now: OffsetDateTime) = dbQuery { + SysMenuTable.update({ + (SysMenuTable.name inList listOf("StatisticsInfoRoot")) and SysMenuTable.deletedAt.isNull() + }) { + it[SysMenuTable.visible] = false + it[SysMenuTable.status] = "DISABLED" + it[SysMenuTable.updatedAt] = now + } + } + // ========================================================= // Dicts // ========================================================= diff --git a/server/src/main/kotlin/com/bbit/ticket/utils/net/PTApi.kt b/server/src/main/kotlin/com/bbit/ticket/utils/net/PTApi.kt new file mode 100644 index 0000000..851dc78 --- /dev/null +++ b/server/src/main/kotlin/com/bbit/ticket/utils/net/PTApi.kt @@ -0,0 +1,89 @@ +package com.bbit.ticket.utils.net + +import com.bbit.ticket.entity.request.AskInvoiceRequest +import com.bbit.ticket.entity.request.AuthQrcodeRequest +import com.bbit.ticket.entity.request.GetLoginSmsCodeRequest +import com.bbit.ticket.entity.request.InvoiceQueryRequest +import com.bbit.ticket.entity.request.QueryDigitalAccountListRequest +import com.bbit.ticket.entity.request.QueryEnterpriseBankAccountRequest +import com.bbit.ticket.entity.request.QueryEnterpriseInfoRequest +import com.bbit.ticket.entity.request.QueryInvoiceRequest +import com.bbit.ticket.entity.request.QueryRealNameAuthQrStatusRequest +import com.bbit.ticket.entity.request.QuickRedInvoiceRequest +import com.bbit.ticket.entity.request.SmsLoginRequest +import com.bbit.ticket.entity.request.TaxBureauAuthReq +import com.bbit.ticket.entity.request.TaxRegister +import com.bbit.ticket.entity.request.TaxRegisterInfo +import com.bbit.ticket.entity.response.AuthQrcodeResponse +import com.bbit.ticket.entity.response.AuthQrcodeStatusResponse +import com.bbit.ticket.entity.response.DigitalAccountInfo +import com.bbit.ticket.entity.response.EnterpriseTaxInfo +import com.bbit.ticket.entity.response.EtaxRegisterResponse +import com.bbit.ticket.entity.response.GetInvoiceInfoResponse +import com.bbit.ticket.entity.response.InvoiceCreateResponse +import com.bbit.ticket.entity.response.InvoiceQueryResponse +import com.bbit.ticket.entity.response.LoginSmsCodeResponse +import com.bbit.ticket.entity.response.QueryEnterpriseBankAccountResponse +import com.bbit.ticket.entity.response.QueryEnterpriseInfoResponse +import com.bbit.ticket.entity.response.QuickRedInvoiceResponse +import com.bbit.ticket.entity.response.SMSLoginResponse +import com.bbit.ticket.entity.response.TaxBureauAccountAuthContent + +object PTApi { + /** 企业注册 2.2*/ + suspend fun registerEnterprise(req: TaxRegisterInfo): EnterpriseTaxInfo = + PTClient.ptPost("register.pt", req) + + /** 登记数电账号 2.3*/ + suspend fun registerDigitalAccount(req: TaxRegister): EtaxRegisterResponse = + PTClient.ptPost("registerUser.pt", req) + + /** 发送登录短信验证码 2.4 */ + suspend fun sendLoginSmsCode(req: GetLoginSmsCodeRequest): LoginSmsCodeResponse = + PTClient.ptPost("sendLoginSmsCode.pt", req) + + /** 短信验证码登录 2.5 */ + suspend fun smsLogin(req: SmsLoginRequest): SMSLoginResponse = + PTClient.ptPost("smsLogin.pt", req) + + /** 获取实名认证二维码 2.6 */ + suspend fun getAuthenticationQrcode(req: AuthQrcodeRequest): AuthQrcodeResponse = + PTClient.ptPost("getAuthenticationQrcode.pt", req) + + /** 查询认证二维码扫码状态 2.7 */ + suspend fun queryAuthQrcodeScanStatus(req: QueryRealNameAuthQrStatusRequest): AuthQrcodeStatusResponse = + PTClient.ptPost("queryAuthQrcodeScanStatus.pt", req) + + /** 查询数电账号认证状态 2.8 */ + suspend fun getTaxBureauAccountAuthStatus(req: TaxBureauAuthReq): TaxBureauAccountAuthContent = + PTClient.ptPost("getTaxBureauAccountAuthStatus.pt", req) + + /** 蓝票接口调用 2.9 */ + suspend fun invoiceBlue(req: AskInvoiceRequest): InvoiceCreateResponse = + PTClient.ptPost("invoiceBlue.pt", req) + + /** 红票接口调用 2.10 */ + suspend fun invoiceRed(req: QuickRedInvoiceRequest): QuickRedInvoiceResponse = + PTClient.ptPost("invoiceRed.pt", req) + + /** 开票统计及授信额度查询 2.20 */ + suspend fun queryAllEleBlueInvStatistics(req: InvoiceQueryRequest): InvoiceQueryResponse = + PTClient.ptPost("queryAllEleBlueInvStatistics.pt", req) + + /** 查询票通同步发票信息 2.12*/ + suspend fun queryInvoiceInfo(req: QueryInvoiceRequest): GetInvoiceInfoResponse = + PTClient.ptPost("queryInvoiceInfo.pt", req) + + /** 查询数电账号列表 2.45 */ + suspend fun listTaxBureauAccount(req: QueryDigitalAccountListRequest): List = + PTClient.ptPost("listTaxBureauAccount.pt", req) + + /** 查询企业状态 2.47 */ + suspend fun getEnterpriseInfo(req: QueryEnterpriseInfoRequest): QueryEnterpriseInfoResponse = + PTClient.ptPost("getEnterpriseInfo.pt", req) + + /** 查询企业开户行及账号 2.49 */ + suspend fun queryEnterpriseBankInfo(req: QueryEnterpriseBankAccountRequest): QueryEnterpriseBankAccountResponse = + PTClient.ptPost("queryEnterpriseBankInfo.pt", req) + +} diff --git a/web/src/api/piaotong/index.ts b/web/src/api/piaotong/index.ts index cca492f..7968ddb 100644 --- a/web/src/api/piaotong/index.ts +++ b/web/src/api/piaotong/index.ts @@ -172,6 +172,10 @@ export function createDigitalAccountApi( return http.post('/pt/digital-accounts', payload) } +export function updateDigitalAccountStatusApi(id: string, status: string): Promise { + return http.put(`/pt/digital-accounts/${id}/status`, { status }) +} + export interface PresetData { bankName: string bankAccount: string diff --git a/web/src/features/piaotong/digital-accounts/index.vue b/web/src/features/piaotong/digital-accounts/index.vue index 688f8dd..851b07a 100644 --- a/web/src/features/piaotong/digital-accounts/index.vue +++ b/web/src/features/piaotong/digital-accounts/index.vue @@ -110,6 +110,7 @@ import { NIcon, NInput, NModal, + NPopconfirm, NSelect, NSpace, NTag, @@ -122,7 +123,8 @@ import { listDigitalAccountsApi, refreshDigitalAccountsApi, sendLoginSmsCodeApi, - smsLoginApi + smsLoginApi, + updateDigitalAccountStatusApi } from '@/api/piaotong' import type { DigitalAccountItem } from '@/api/piaotong' import { useAuthStore } from '@/stores/auth' @@ -144,6 +146,7 @@ const selected = ref(null) const createFormRef = ref(null) const canManage = computed(() => authStore.user?.userType !== 'DIGITAL_OPERATOR') +const canUpdateStatus = computed(() => authStore.hasPermission('digital-account:status')) const createForm = reactive({ account: '', @@ -197,6 +200,17 @@ const columns: DataTableColumns = [ ) }, { title: '最近认证', key: 'lastAuthSuccTime', minWidth: 160 }, + { + title: '平台状态', + key: 'status', + width: 110, + render: (row) => + h( + NTag, + { type: row.status === 'ENABLED' ? 'success' : 'warning' }, + { default: () => (row.status === 'ENABLED' ? '可用' : '禁用') } + ) + }, { title: 'API Key', key: 'apiKey', @@ -207,19 +221,49 @@ const columns: DataTableColumns = [ title: '操作', key: 'actions', fixed: 'right', - width: 220, + width: 300, render: (row) => h('div', { class: 'row-actions' }, [ h( NButton, - { size: 'small', secondary: true, onClick: () => openSms(row) }, + { + size: 'small', + secondary: true, + disabled: row.status !== 'ENABLED', + onClick: () => openSms(row) + }, { icon: () => h(NIcon, { component: KeyRound }), default: () => '短信登录' } ), h( NButton, - { size: 'small', tertiary: true, onClick: () => openQrcode(row) }, + { + size: 'small', + tertiary: true, + disabled: row.status !== 'ENABLED', + onClick: () => openQrcode(row) + }, { icon: () => h(NIcon, { component: ShieldCheck }), default: () => '认证' } - ) + ), + canUpdateStatus.value + ? h( + NPopconfirm, + { + onPositiveClick: () => updateAccountStatus(row) + }, + { + trigger: () => + h( + NButton, + { size: 'small', tertiary: true, type: row.status === 'ENABLED' ? 'warning' : 'success' }, + { default: () => (row.status === 'ENABLED' ? '禁用' : '恢复') } + ), + default: () => + row.status === 'ENABLED' + ? `确认禁用数电账号 ${row.account} 吗?` + : `确认恢复数电账号 ${row.account} 吗?` + } + ) + : null ]) } ] @@ -270,6 +314,13 @@ async function createAccount() { } } +async function updateAccountStatus(row: DigitalAccountItem) { + const nextStatus = row.status === 'ENABLED' ? 'DISABLED' : 'ENABLED' + await updateDigitalAccountStatusApi(row.id, nextStatus) + message.success(nextStatus === 'ENABLED' ? '数电账号已恢复' : '数电账号已禁用') + await load() +} + async function openSms(row: DigitalAccountItem) { selected.value = row smsCode.value = '' diff --git a/web/src/features/piaotong/invoice-issue/index.vue b/web/src/features/piaotong/invoice-issue/index.vue index 8013392..b417e1d 100644 --- a/web/src/features/piaotong/invoice-issue/index.vue +++ b/web/src/features/piaotong/invoice-issue/index.vue @@ -400,7 +400,6 @@ style="color: #e74c3c; font-size: 12px" >农产品开票:销方信息代表实际的购方信息 - 不填则使用平台默认配置
diff --git a/web/src/features/system/users/index.vue b/web/src/features/system/users/index.vue index b8e9534..1b0736c 100644 --- a/web/src/features/system/users/index.vue +++ b/web/src/features/system/users/index.vue @@ -102,26 +102,6 @@
-
-
税务信息
-
-
- {{ item.label }} - {{ item.value }} -
-
-
- -
-
银行与预设信息
-
-
- {{ item.label }} - {{ item.value }} -
-
-
-
系统信息
@@ -342,36 +322,6 @@ const baseDetailItems = computed(() => { ] }) -const taxDetailItems = computed(() => { - const user = detailUser.value - if (!user) return [] - return [ - { label: '纳税人识别号', value: displayValue(user.taxpayerNum) }, - { label: '数电账号', value: displayValue(user.account) }, - { label: '身份类型', value: displayValue(user.taxIdentityType) }, - { label: '联系人', value: displayValue(user.taxContactName) }, - { label: '联系人电话', value: displayValue(user.taxContactPhone) }, - { label: '联系人邮箱', value: displayValue(user.taxContactEmail) }, - { label: '法定代表人', value: displayValue(user.taxLegalPersonName) }, - { label: '企业名称', value: displayValue(user.taxEnterpriseName) }, - { label: '地区编码', value: displayValue(user.taxRegionCode) }, - { label: '城市', value: displayValue(user.taxCityName) }, - { label: '企业地址', value: displayValue(user.taxEnterpriseAddress) }, - { label: '税务登记证', value: displayValue(user.taxRegistrationCertificate) } - ] -}) - -const presetDetailItems = computed(() => { - const user = detailUser.value - if (!user) return [] - return [ - { label: '开户行', value: displayValue(user.bankName) }, - { label: '银行账号', value: displayValue(user.bankAccount) }, - { label: '预设地址', value: displayValue(user.presetAddress) }, - { label: '预设电话', value: displayValue(user.presetPhone) } - ] -}) - const systemDetailItems = computed(() => { const user = detailUser.value if (!user) return [] diff --git a/web/src/types/system/user.ts b/web/src/types/system/user.ts index 802cf0c..2bfc11d 100644 --- a/web/src/types/system/user.ts +++ b/web/src/types/system/user.ts @@ -36,22 +36,6 @@ export interface UserDetail { deletedAt?: string | null deletedBy?: string | null version: number - taxpayerNum?: string | null - account?: string | null - taxIdentityType?: string | null - taxContactName?: string | null - taxContactPhone?: string | null - taxContactEmail?: string | null - taxLegalPersonName?: string | null - taxEnterpriseName?: string | null - taxRegionCode?: string | null - taxCityName?: string | null - taxEnterpriseAddress?: string | null - taxRegistrationCertificate?: string | null - bankName?: string | null - bankAccount?: string | null - presetAddress?: string | null - presetPhone?: string | null } export interface UserRoleBrief { @@ -90,10 +74,6 @@ export interface UpdateUserRequest { email?: string avatar?: string orgId?: string - taxpayerNum?: string - account?: string - taxPassword?: string - taxIdentityType?: string } export interface UpdateUserStatusRequest {