From 8930029f8fd7bebe3ff2b8a418d3601ce1537e77 Mon Sep 17 00:00:00 2001 From: JilingLee <18850011309@139.com> Date: Thu, 21 Sep 2023 14:42:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=91=E7=A5=A8=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/accounting20230921JilingLee.sql | 96 +++ .../enums/AccountingStatusEnum.java | 25 + .../accounting/enums/ErrorCodeConstants.java | 1 + .../admin/invoices/InvoicesController.java | 198 ++++++ .../admin/invoices/vo/InvoicesBaseVO.java | 215 ++++++ .../invoices/vo/InvoicesCreateReqVO.java | 14 + .../admin/invoices/vo/InvoicesExcelVO.java | 213 ++++++ .../invoices/vo/InvoicesExportReqVO.java | 210 ++++++ .../admin/invoices/vo/InvoicesPageReqVO.java | 211 ++++++ .../admin/invoices/vo/InvoicesRespVO.java | 19 + .../invoices/vo/InvoicesUpdateReqVO.java | 18 + .../vo/VoucherDetailsBaseVO.java | 1 - .../convert/invoices/InvoicesConvert.java | 34 + .../dataobject/invoices/BaiduInvoicesDO.java | 147 ++++ .../dal/dataobject/invoices/Converter.java | 68 ++ .../dal/dataobject/invoices/InvoicesDO.java | 286 ++++++++ .../invoices/invoiceVerification.java | 313 +++++++++ .../dal/mysql/invoices/InvoicesMapper.java | 156 +++++ .../service/invoices/InvoicesService.java | 70 ++ .../service/invoices/InvoicesServiceImpl.java | 82 +++ .../mapper/invoices/InvoicesMapper.xml | 12 + .../invoices/InvoicesServiceImplTest.java | 647 ++++++++++++++++++ .../module/bs/utils/BaiduOcrConstant.java | 14 +- .../module/bs/utils/BaiduOcrHandler.java | 103 ++- 24 files changed, 3149 insertions(+), 4 deletions(-) create mode 100644 sql/accounting20230921JilingLee.sql create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/InvoicesController.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesBaseVO.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesCreateReqVO.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesExcelVO.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesExportReqVO.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesPageReqVO.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesRespVO.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesUpdateReqVO.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/convert/invoices/InvoicesConvert.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/BaiduInvoicesDO.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/Converter.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/InvoicesDO.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/invoiceVerification.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/mysql/invoices/InvoicesMapper.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesService.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesServiceImpl.java create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/main/resources/mapper/invoices/InvoicesMapper.xml create mode 100644 yudao-module-accounting/yudao-module-accounting-biz/src/test/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesServiceImplTest.java diff --git a/sql/accounting20230921JilingLee.sql b/sql/accounting20230921JilingLee.sql new file mode 100644 index 00000000..3357699a --- /dev/null +++ b/sql/accounting20230921JilingLee.sql @@ -0,0 +1,96 @@ +-- ---------------------------- +-- 发票表 for accounting_invoices +-- ---------------------------- +DROP TABLE IF EXISTS `accounting_invoices`; +CREATE TABLE `accounting_invoices` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '发票id', + `voucher_id` bigint(20) NULL DEFAULT NULL COMMENT '凭证id,一个凭证对应多个电子发票', + `invoice_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '发票代码', + `invoice_num` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '发票号码', + `amountIn_words` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '大写金额', + `price` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '单价', + `total_tax` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '合计税额', + `tax_rate` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '税率', + `total_amount` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '金额', + `commodity_tax` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '税额', + `commodity_amount` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '价税合计', + `amountIn_figuers` varchar(55) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '小写价税合计', + `fote_drawer` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '开票人', + `seller_address` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '销方地址电话', + `commodity_num` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '服务条数', + `seller_register_num` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '销方纳税识别号', + `machine_code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '报送状态', + `remarks` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `seller_bank` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '销方开户行及账号', + `check_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '校验码', + `invoice_date` datetime(0) NULL DEFAULT NULL COMMENT '开票日期', + `purchaser_register_num` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '购方税号', + `invoice_type_org` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '清单标志', + `PASSWORD` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '密码区', + `agent` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '打印标志', + `purchaser_bank` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '购方开户行及账号', + `checker` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '复核人', + `city` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '城市', + `purchaser_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '购方公司名', + `commodity_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '规格型号', + `province` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '报送日志', + `invoice_type` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发票种类', + `sheet_num` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发票联', + `purchaser_address` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '购方地址电话', + `commodity_unit` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '部门', + `payee` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收款人', + `commodity_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '主要商品名称', + `seller_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '销方名称', + `invoice_check` tinyint(10) NULL DEFAULT NULL COMMENT '审核状态0待审核1已审核2审核退回3未提交', + `invoice_seal` tinyint(10) NULL DEFAULT NULL COMMENT '是否印章0,1', + `invoice_qrcode` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发票综合代码', + `invoice_qrnum` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发票综合号码', + `qr_check_code` tinyint(10) NULL DEFAULT NULL COMMENT '二维码查验(1查询相符,0查验不符)', + `invoice_state` tinyint(10) NULL DEFAULT NULL COMMENT '发票状态1正常0作废', + `print_num` datetime(0) NULL DEFAULT NULL COMMENT '作废日期', + `inout_mark` tinyint(10) NULL DEFAULT NULL COMMENT '进销项标识0进项1销项', + `invalid_mark` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '作废标志0作废1启用', + `duplicate_mark` tinyint(10) NULL DEFAULT NULL COMMENT '重复标识0已查重1有重复', + `check_true` tinyint(10) NULL DEFAULT NULL COMMENT '验真0未验真1已验证', + `encrypt` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '加密', + `create_by` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '制单人', + `creator` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '创建者', + `create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间', + `update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间', + `record_id` bigint(20) NULL DEFAULT NULL COMMENT '归档id,一个归档id对应多个发票', + `company_id` bigint(20) NULL DEFAULT NULL COMMENT '业务实体id', + `company` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '业务实体', + `dept_id` bigint(20) NULL DEFAULT NULL COMMENT '所属部门id', + `dept_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '所属部门', + `user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户id', + `deleted` bit(1) NULL DEFAULT b'0' COMMENT '是否删除', + `updater` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '更新者', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注', + `attr1` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '预留字段1', + `attr2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '预留字段2', + `attr3` int(11) NULL DEFAULT NULL COMMENT '预留字段3', + `attr4` int(11) NULL DEFAULT NULL COMMENT '预留字段4', + `archive_state` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '归档状态', + `tenant_id` bigint(20) NULL DEFAULT NULL COMMENT '租户编号,一个集团/总公司对应一个租户', + `file_url` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '发票地址', + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 16 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '发票表' ROW_FORMAT = Dynamic; + +SET FOREIGN_KEY_CHECKS = 1; + +-- 插入发票菜单 +SELECT * FROM `system_menu` WHERE `name`='会计档案'; +SET @menuId = LAST_INSERT_ID(); +INSERT INTO `lyr-one`.`system_menu`(`name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES ('发票管理', '', 2, 0, @menuId, 'invoices', '', 'accounting/invoices/index', 'Invoices', 0, b'1', b'1', b'1', '', '2023-09-20 14:03:48', '', '2023-09-20 14:03:48', b'0'); +SET @menuId2 = LAST_INSERT_ID(); +INSERT INTO `lyr-one`.`system_menu`(`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (NULL, '发票查询', 'accounting:invoices:query', 3, 1, @menuId2, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-20 14:03:48', '', '2023-09-20 14:03:48', b'0'); +INSERT INTO `lyr-one`.`system_menu`(`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (NULL, '发票创建', 'accounting:invoices:create', 3, 2, @menuId2, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-20 14:03:48', '', '2023-09-20 14:03:48', b'0'); +INSERT INTO `lyr-one`.`system_menu`(`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (NULL, '发票更新', 'accounting:invoices:update', 3, 3, @menuId2, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-20 14:03:48', '', '2023-09-20 14:03:48', b'0'); +INSERT INTO `lyr-one`.`system_menu`(`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (NULL, '发票删除', 'accounting:invoices:delete', 3, 4, @menuId2, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-20 14:03:48', '', '2023-09-20 14:03:48', b'0'); +INSERT INTO `lyr-one`.`system_menu`(`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (NULL, '发票导出', 'accounting:invoices:export', 3, 5, @menuId2, '', '', '', NULL, 0, b'1', b'1', b'1', '', '2023-09-20 14:03:48', '', '2023-09-20 14:03:48', b'0'); + + +-- 插入发票字典 +INSERT INTO `lyr-one`.`system_dict_type`(`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (190, '会计发票查验', 'accounting_invoices_check', 0, NULL, '', '2023-09-21 14:15:03', '', '2023-09-21 14:15:03', b'0', '1970-01-01 00:00:00'); +INSERT INTO `lyr-one`.`system_dict_type`(`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (191, '会计发票查重', 'accounting_invoices_duplicate', 0, NULL, '', '2023-09-21 14:16:49', '', '2023-09-21 14:17:27', b'0', '1970-01-01 00:00:00'); + diff --git a/yudao-module-accounting/yudao-module-accounting-api/src/main/java/cn/iocoder/yudao/module/accounting/enums/AccountingStatusEnum.java b/yudao-module-accounting/yudao-module-accounting-api/src/main/java/cn/iocoder/yudao/module/accounting/enums/AccountingStatusEnum.java index 19d76943..b2ec0310 100644 --- a/yudao-module-accounting/yudao-module-accounting-api/src/main/java/cn/iocoder/yudao/module/accounting/enums/AccountingStatusEnum.java +++ b/yudao-module-accounting/yudao-module-accounting-api/src/main/java/cn/iocoder/yudao/module/accounting/enums/AccountingStatusEnum.java @@ -9,6 +9,29 @@ import lombok.Getter; @AllArgsConstructor @Getter public enum AccountingStatusEnum { + /**增值税电子专用发票:elec_special_vat_invoice + * 增值税普通发票:normal_invoice + * 增值税普通发票(电子):elec_normal_invoice + * 增值税普通发票(卷式):roll_normal_invoice + * 通行费增值税电子普通发票:toll_elec_normal_invoice + * 区块链电子发票(目前仅支持深圳地区):blockchain_invoice + * 全电发票(专用发票):elec_invoice_special + * 全电发票(普通发票):elec_invoice_normal + * 货运运输业增值税专用发票:special_freight_transport_invoice + * 机动车销售发票:motor_vehicle_invoice + * 二手车销售发票:used_vehicle_invoice + * */ + ELEC_SPECIAL_VAT_INVOICE("elec_special_vat_invoice","增值税电子专用发票"), + NORMAL_INVOICE("normal_invoice","增值税普通发票"), + ELEC_NORMAL_INVOICE("elec_normal_invoice","增值税普通发票(电子)"), + + + /** + * 查重 + */ + DUPLICATE_INVOICE("1","重复"), + UN_DUPLICATE_INVOICE("0","不重复"), + INCOMPLETE("0", "不完整"), COMPLETE("1", "完整"), @@ -18,6 +41,8 @@ public enum AccountingStatusEnum { BORROWED("1", "已借阅"); + + /** * 类型 */ diff --git a/yudao-module-accounting/yudao-module-accounting-api/src/main/java/cn/iocoder/yudao/module/accounting/enums/ErrorCodeConstants.java b/yudao-module-accounting/yudao-module-accounting-api/src/main/java/cn/iocoder/yudao/module/accounting/enums/ErrorCodeConstants.java index e6d3c045..08dc9fcc 100644 --- a/yudao-module-accounting/yudao-module-accounting-api/src/main/java/cn/iocoder/yudao/module/accounting/enums/ErrorCodeConstants.java +++ b/yudao-module-accounting/yudao-module-accounting-api/src/main/java/cn/iocoder/yudao/module/accounting/enums/ErrorCodeConstants.java @@ -4,4 +4,5 @@ import cn.iocoder.yudao.framework.common.exception.ErrorCode; public interface ErrorCodeConstants { ErrorCode VOUCHER_NOT_EXISTS = new ErrorCode(200100, "会计凭证不存在"); ErrorCode VOUCHER_DETAILS_NOT_EXISTS = new ErrorCode(300100, "凭证详情不存在"); + ErrorCode INVOICES_NOT_EXISTS = new ErrorCode(400100, "发票不存在"); } \ No newline at end of file diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/InvoicesController.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/InvoicesController.java new file mode 100644 index 00000000..0f547efb --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/InvoicesController.java @@ -0,0 +1,198 @@ +package cn.iocoder.yudao.module.accounting.controller.admin.invoices; + +import cn.hutool.core.io.IoUtil; +import cn.iocoder.yudao.framework.common.util.FileUtils; +import cn.iocoder.yudao.framework.common.util.barcode.BarcodeUtil; +import cn.iocoder.yudao.module.accounting.dal.dataobject.invoices.BaiduInvoicesDO; +import cn.iocoder.yudao.module.accounting.dal.dataobject.invoices.Converter; +import cn.iocoder.yudao.module.accounting.enums.AccountingStatusEnum; +import cn.iocoder.yudao.module.bs.utils.BaiduOcrHandler; +import cn.iocoder.yudao.module.infra.service.file.FileService; +import com.alibaba.fastjson.JSONObject; +import me.zhyd.oauth.log.Log; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; + +import org.springframework.validation.annotation.Validated; +import org.springframework.security.access.prepost.PreAuthorize; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; + +import javax.validation.*; +import javax.servlet.http.*; +import java.io.File; +import java.util.*; +import java.io.IOException; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; + +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; + +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.*; + +import cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo.*; +import cn.iocoder.yudao.module.accounting.dal.dataobject.invoices.InvoicesDO; +import cn.iocoder.yudao.module.accounting.convert.invoices.InvoicesConvert; +import cn.iocoder.yudao.module.accounting.service.invoices.InvoicesService; +import org.springframework.web.multipart.MultipartFile; + +@Tag(name = "管理后台 - 发票") +@RestController +@RequestMapping("/accounting/invoices") +@Validated +public class InvoicesController { + + @Resource + private InvoicesService invoicesService; + @Resource + private FileService fileService; + + @PostMapping("/create") + @Operation(summary = "创建发票") + @PreAuthorize("@ss.hasPermission('accounting:invoices:create')") + public CommonResult createInvoices(@Valid @RequestBody InvoicesCreateReqVO createReqVO) { + return success(invoicesService.createInvoices(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新发票") + @PreAuthorize("@ss.hasPermission('accounting:invoices:update')") + public CommonResult updateInvoices(@Valid @RequestBody InvoicesUpdateReqVO updateReqVO) { + invoicesService.updateInvoices(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除发票") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('accounting:invoices:delete')") + public CommonResult deleteInvoices(@RequestParam("id") Long id) { + invoicesService.deleteInvoices(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得发票") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('accounting:invoices:query')") + public CommonResult getInvoices(@RequestParam("id") Long id) { + InvoicesDO invoices = invoicesService.getInvoices(id); + return success(InvoicesConvert.INSTANCE.convert(invoices)); + } + + @GetMapping("/list") + @Operation(summary = "获得发票列表") + @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048") + @PreAuthorize("@ss.hasPermission('accounting:invoices:query')") + public CommonResult> getInvoicesList(@RequestParam("ids") Collection ids) { + List list = invoicesService.getInvoicesList(ids); + return success(InvoicesConvert.INSTANCE.convertList(list)); + } + + @GetMapping("/page") + @Operation(summary = "获得发票分页") + @PreAuthorize("@ss.hasPermission('accounting:invoices:query')") + public CommonResult> getInvoicesPage(@Valid InvoicesPageReqVO pageVO) { + PageResult pageResult = invoicesService.getInvoicesPage(pageVO); + return success(InvoicesConvert.INSTANCE.convertPage(pageResult)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出发票 Excel") + @PreAuthorize("@ss.hasPermission('accounting:invoices:export')") + @OperateLog(type = EXPORT) + public void exportInvoicesExcel(@Valid InvoicesExportReqVO exportReqVO, + HttpServletResponse response) throws IOException { + List list = invoicesService.getInvoicesList(exportReqVO); + // 导出 Excel + List datas = InvoicesConvert.INSTANCE.convertList02(list); + ExcelUtils.write(response, "发票.xls", "数据", InvoicesExcelVO.class, datas); + } + + @PostMapping("/identify") + @Operation(summary = "发票识别") + public CommonResult identify(@RequestParam("multipartFile") MultipartFile multipartFile) throws Exception { + String imageBase64Param = BaiduOcrHandler.getImageBase64Param(multipartFile); + String originalFileName = multipartFile.getOriginalFilename(); + int lastDotIndex = originalFileName.lastIndexOf("."); + String fileExtension = originalFileName.substring(lastDotIndex + 1); + JSONObject ocrResult = null; + //发票识别 + if (fileExtension.equalsIgnoreCase("ofd")) { + ocrResult = BaiduOcrHandler.invoiceOCR(imageBase64Param, "ofd"); + } + if (fileExtension.equalsIgnoreCase("pdf")) { + ocrResult = BaiduOcrHandler.invoiceOCR(imageBase64Param, "pdf"); + } + BaiduInvoicesDO parse = JSONObject.toJavaObject(ocrResult, BaiduInvoicesDO.class); + InvoicesCreateReqVO invoicesDO = Converter.convertInvoiceToInvoicesDO(parse); + //发票验真 +// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); +// String dateFormat = invoicesDO.getInvoiceDate().format(formatter); +// String checkCode = invoicesDO.getCheckCode(); +// String lastSixDigits = checkCode.substring(checkCode.length() - 6); +// JSONObject jsonObjectVer = BaiduOcrHandler.invoiceVerification(invoicesDO.getInvoiceCode(), +// invoicesDO.getInvoiceNum(), +// dateFormat, +// AccountingStatusEnum.ELEC_NORMAL_INVOICE.getValue(), +// lastSixDigits, +// invoicesDO.getTotalAmount()); +// byte num = 0; +// if (jsonObjectVer.get("VerifyResult").equals("0001")) { +// num = 1; +// invoicesDO.setQrCheckCode(num); +// } else { +// invoicesDO.setQrCheckCode(num); +// if (jsonObjectVer.get("VerifyMessage") != null) { +// return error("验真失败" + jsonObjectVer.get("VerifyMessage")); +// } +// } + //发票查重 + InvoicesExportReqVO queryIn = new InvoicesExportReqVO(); + queryIn.setInvoiceCode(invoicesDO.getInvoiceCode()); + queryIn.setInvoiceNum(invoicesDO.getInvoiceNum()); + List invoicesList = invoicesService.getInvoicesList(queryIn); + if (invoicesList.size()>0){ + invoicesDO.setDuplicateMark(Byte.valueOf(AccountingStatusEnum.DUPLICATE_INVOICE.getValue())); + }else { + invoicesDO.setDuplicateMark(Byte.valueOf(AccountingStatusEnum.UN_DUPLICATE_INVOICE.getValue())); + } + String url = getUrl(multipartFile); + invoicesDO.setFileUrl(url); + invoicesService.createInvoices(invoicesDO); + return success(invoicesDO); + } + + + @PostMapping("/verification") + @Operation(summary = "发票验真") + public CommonResult verification(@RequestParam("invoice_code") String invoice_code, + @RequestParam("invoice_num") String invoice_num, + @RequestParam("invoice_date") String invoice_date, + @RequestParam("invoice_type") String invoice_type, + @RequestParam("check_code") String check_code, + @RequestParam("total_amount") String total_amount) throws Exception { + JSONObject jsonObjectVer = BaiduOcrHandler.invoiceVerification(invoice_code, invoice_num, invoice_date, invoice_type, + check_code, total_amount); + return success(jsonObjectVer); + } + + + /** + * 获取发票地址 + * @param file + * @return + */ + private String getUrl(MultipartFile file) throws Exception{ + String url=""; + url = fileService.createFile(null, null, IoUtil.readBytes(file.getInputStream())); + return url; + } +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesBaseVO.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesBaseVO.java new file mode 100644 index 00000000..5748a8dc --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesBaseVO.java @@ -0,0 +1,215 @@ +package cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import javax.validation.constraints.*; +import org.springframework.format.annotation.DateTimeFormat; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +/** + * 发票 Base VO,提供给添加、修改、详细的子 VO 使用 + * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成 + */ +@Data +public class InvoicesBaseVO { + + @Schema(description = "凭证id,一个凭证对应多个电子发票", requiredMode = Schema.RequiredMode.REQUIRED, example = "25675") + private Long voucherId; + + @Schema(description = "发票代码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "发票代码不能为空") + private String invoiceCode; + + @Schema(description = "发票号码", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "发票号码不能为空") + private String invoiceNum; + + @Schema(description = "大写金额") + private String amountinWords; + + @Schema(description = "单价", example = "29904") + private String price; + + @Schema(description = "合计税额") + private String totalTax; + + @Schema(description = "税率") + private String taxRate; + + @Schema(description = "金额") + private String totalAmount; + + @Schema(description = "税额") + private String commodityTax; + + @Schema(description = "价税合计") + private String commodityAmount; + + @Schema(description = "小写价税合计") + private String amountinFiguers; + + @Schema(description = "开票人") + private String foteDrawer; + + @Schema(description = "销方地址电话") + private String sellerAddress; + + @Schema(description = "服务条数") + private String commodityNum; + + @Schema(description = "销方纳税识别号") + private String sellerRegisterNum; + + @Schema(description = "报送状态") + private String machineCode; + + @Schema(description = "备注") + private String remarks; + + @Schema(description = "销方开户行及账号") + private String sellerBank; + + @Schema(description = "校验码") + private String checkCode; + + @Schema(description = "开票日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime invoiceDate; + + @Schema(description = "购方税号") + private String purchaserRegisterNum; + + @Schema(description = "清单标志") + private String invoiceTypeOrg; + + @Schema(description = "密码区") + private String password; + + @Schema(description = "打印标志") + private String agent; + + @Schema(description = "购方开户行及账号") + private String purchaserBank; + + @Schema(description = "复核人") + private String checker; + + @Schema(description = "城市") + private String city; + + @Schema(description = "购方公司名", example = "芋艿") + private String purchaserName; + + @Schema(description = "规格型号", example = "1") + private String commodityType; + + @Schema(description = "报送日志") + private String province; + + @Schema(description = "发票种类", example = "1") + private String invoiceType; + + @Schema(description = "发票联") + private String sheetNum; + + @Schema(description = "购方地址电话") + private String purchaserAddress; + + @Schema(description = "部门") + private String commodityUnit; + + @Schema(description = "收款人") + private String payee; + + @Schema(description = "主要商品名称", example = "张三") + private String commodityName; + + @Schema(description = "销方名称", example = "王五") + private String sellerName; + + @Schema(description = "审核状态0待审核1已审核2审核退回3未提交") + private Byte invoiceCheck; + + @Schema(description = "是否印章0,1") + private Byte invoiceSeal; + + @Schema(description = "发票综合代码") + private String invoiceQrcode; + + @Schema(description = "发票综合号码") + private String invoiceQrnum; + + @Schema(description = "二维码查验(1查询相符,0查验不符)") + private Byte qrCheckCode; + + @Schema(description = "发票状态1正常0作废") + private Byte invoiceState; + + @Schema(description = "作废日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime printNum; + + @Schema(description = "进销项标识0进项1销项") + private Byte inoutMark; + + @Schema(description = "作废标志0作废1启用") + private String invalidMark; + + @Schema(description = "重复标识0已查重1有重复") + private Byte duplicateMark; + + @Schema(description = "验真0未验真1已验证") + private Byte checkTrue; + + @Schema(description = "加密") + private String encrypt; + + @Schema(description = "制单人") + private String createBy; + + @Schema(description = "归档id,一个归档id对应多个发票", example = "26489") + private Long recordId; + + @Schema(description = "业务实体id", example = "17678") + private Long companyId; + + @Schema(description = "业务实体") + private String company; + + @Schema(description = "所属部门id", example = "7722") + private Long deptId; + + @Schema(description = "所属部门", example = "赵六") + private String deptName; + + @Schema(description = "用户id", example = "12438") + private Long userId; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "预留字段1") + private String attr1; + + @Schema(description = "预留字段2") + private String attr2; + + @Schema(description = "预留字段3") + private Integer attr3; + + @Schema(description = "预留字段4") + private Integer attr4; + + @Schema(description = "归档状态") + private String archiveState; + + @Schema(description = "发票地址") + private String fileUrl; + +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesCreateReqVO.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesCreateReqVO.java new file mode 100644 index 00000000..6fac7a01 --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesCreateReqVO.java @@ -0,0 +1,14 @@ +package cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - 发票创建 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InvoicesCreateReqVO extends InvoicesBaseVO { + +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesExcelVO.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesExcelVO.java new file mode 100644 index 00000000..36ef3f7d --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesExcelVO.java @@ -0,0 +1,213 @@ +package cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.time.LocalDateTime; + +import com.alibaba.excel.annotation.ExcelProperty; + +/** + * 发票 Excel VO + * + * @author 芋道源码 + */ +@Data +public class InvoicesExcelVO { + + @ExcelProperty("发票id") + private Long id; + + @ExcelProperty("凭证id,一个凭证对应多个电子发票") + private Long voucherId; + + @ExcelProperty("发票代码") + private String invoiceCode; + + @ExcelProperty("发票号码") + private String invoiceNum; + + @ExcelProperty("大写金额") + private String amountinWords; + + @ExcelProperty("单价") + private String price; + + @ExcelProperty("合计税额") + private String totalTax; + + @ExcelProperty("税率") + private String taxRate; + + @ExcelProperty("金额") + private String totalAmount; + + @ExcelProperty("税额") + private String commodityTax; + + @ExcelProperty("价税合计") + private String commodityAmount; + + @ExcelProperty("小写价税合计") + private String amountinFiguers; + + @ExcelProperty("开票人") + private String foteDrawer; + + @ExcelProperty("销方地址电话") + private String sellerAddress; + + @ExcelProperty("服务条数") + private String commodityNum; + + @ExcelProperty("销方纳税识别号") + private String sellerRegisterNum; + + @ExcelProperty("报送状态") + private String machineCode; + + @ExcelProperty("备注") + private String remarks; + + @ExcelProperty("销方开户行及账号") + private String sellerBank; + + @ExcelProperty("校验码") + private String checkCode; + + @ExcelProperty("开票日期") + private LocalDateTime invoiceDate; + + @ExcelProperty("购方税号") + private String purchaserRegisterNum; + + @ExcelProperty("清单标志") + private String invoiceTypeOrg; + + @ExcelProperty("密码区") + private String password; + + @ExcelProperty("打印标志") + private String agent; + + @ExcelProperty("购方开户行及账号") + private String purchaserBank; + + @ExcelProperty("复核人") + private String checker; + + @ExcelProperty("城市") + private String city; + + @ExcelProperty("购方公司名") + private String purchaserName; + + @ExcelProperty("规格型号") + private String commodityType; + + @ExcelProperty("报送日志") + private String province; + + @ExcelProperty("发票种类") + private String invoiceType; + + @ExcelProperty("发票联") + private String sheetNum; + + @ExcelProperty("购方地址电话") + private String purchaserAddress; + + @ExcelProperty("部门") + private String commodityUnit; + + @ExcelProperty("收款人") + private String payee; + + @ExcelProperty("主要商品名称") + private String commodityName; + + @ExcelProperty("销方名称") + private String sellerName; + + @ExcelProperty("审核状态0待审核1已审核2审核退回3未提交") + private Byte invoiceCheck; + + @ExcelProperty("是否印章0,1") + private Byte invoiceSeal; + + @ExcelProperty("发票综合代码") + private String invoiceQrcode; + + @ExcelProperty("发票综合号码") + private String invoiceQrnum; + + @ExcelProperty("二维码查验(1查询相符,0查验不符)") + private Byte qrCheckCode; + + @ExcelProperty("发票状态1正常0作废") + private Byte invoiceState; + + @ExcelProperty("作废日期") + private LocalDateTime printNum; + + @ExcelProperty("进销项标识0进项1销项") + private Byte inoutMark; + + @ExcelProperty("作废标志0作废1启用") + private String invalidMark; + + @ExcelProperty("重复标识0已查重1有重复") + private Byte duplicateMark; + + @ExcelProperty("验真0未验真1已验证") + private Byte checkTrue; + + @ExcelProperty("加密") + private String encrypt; + + @ExcelProperty("制单人") + private String createBy; + + @ExcelProperty("创建时间") + private LocalDateTime createTime; + + @ExcelProperty("归档id,一个归档id对应多个发票") + private Long recordId; + + @ExcelProperty("业务实体id") + private Long companyId; + + @ExcelProperty("业务实体") + private String company; + + @ExcelProperty("所属部门id") + private Long deptId; + + @ExcelProperty("所属部门") + private String deptName; + + @ExcelProperty("用户id") + private Long userId; + + @ExcelProperty("备注") + private String remark; + + @ExcelProperty("预留字段1") + private String attr1; + + @ExcelProperty("预留字段2") + private String attr2; + + @ExcelProperty("预留字段3") + private Integer attr3; + + @ExcelProperty("预留字段4") + private Integer attr4; + + @ExcelProperty("归档状态") + private String archiveState; + +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesExportReqVO.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesExportReqVO.java new file mode 100644 index 00000000..5aad2a22 --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesExportReqVO.java @@ -0,0 +1,210 @@ +package cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import java.time.LocalDateTime; +import org.springframework.format.annotation.DateTimeFormat; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 发票 Excel 导出 Request VO,参数和 InvoicesPageReqVO 是一致的") +@Data +public class InvoicesExportReqVO { + + @Schema(description = "凭证id,一个凭证对应多个电子发票", example = "25675") + private Long voucherId; + + @Schema(description = "发票代码") + private String invoiceCode; + + @Schema(description = "发票号码") + private String invoiceNum; + + @Schema(description = "大写金额") + private String amountinWords; + + @Schema(description = "单价", example = "29904") + private String price; + + @Schema(description = "合计税额") + private String totalTax; + + @Schema(description = "税率") + private String taxRate; + + @Schema(description = "金额") + private String totalAmount; + + @Schema(description = "税额") + private String commodityTax; + + @Schema(description = "价税合计") + private String commodityAmount; + + @Schema(description = "小写价税合计") + private String amountinFiguers; + + @Schema(description = "开票人") + private String foteDrawer; + + @Schema(description = "销方地址电话") + private String sellerAddress; + + @Schema(description = "服务条数") + private String commodityNum; + + @Schema(description = "销方纳税识别号") + private String sellerRegisterNum; + + @Schema(description = "报送状态") + private String machineCode; + + @Schema(description = "备注") + private String remarks; + + @Schema(description = "销方开户行及账号") + private String sellerBank; + + @Schema(description = "校验码") + private String checkCode; + + @Schema(description = "开票日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] invoiceDate; + + @Schema(description = "购方税号") + private String purchaserRegisterNum; + + @Schema(description = "清单标志") + private String invoiceTypeOrg; + + @Schema(description = "密码区") + private String password; + + @Schema(description = "打印标志") + private String agent; + + @Schema(description = "购方开户行及账号") + private String purchaserBank; + + @Schema(description = "复核人") + private String checker; + + @Schema(description = "城市") + private String city; + + @Schema(description = "购方公司名", example = "芋艿") + private String purchaserName; + + @Schema(description = "规格型号", example = "1") + private String commodityType; + + @Schema(description = "报送日志") + private String province; + + @Schema(description = "发票种类", example = "1") + private String invoiceType; + + @Schema(description = "发票联") + private String sheetNum; + + @Schema(description = "购方地址电话") + private String purchaserAddress; + + @Schema(description = "部门") + private String commodityUnit; + + @Schema(description = "收款人") + private String payee; + + @Schema(description = "主要商品名称", example = "张三") + private String commodityName; + + @Schema(description = "销方名称", example = "王五") + private String sellerName; + + @Schema(description = "审核状态0待审核1已审核2审核退回3未提交") + private Byte invoiceCheck; + + @Schema(description = "是否印章0,1") + private Byte invoiceSeal; + + @Schema(description = "发票综合代码") + private String invoiceQrcode; + + @Schema(description = "发票综合号码") + private String invoiceQrnum; + + @Schema(description = "二维码查验(1查询相符,0查验不符)") + private Byte qrCheckCode; + + @Schema(description = "发票状态1正常0作废") + private Byte invoiceState; + + @Schema(description = "作废日期") + private LocalDateTime printNum; + + @Schema(description = "进销项标识0进项1销项") + private Byte inoutMark; + + @Schema(description = "作废标志0作废1启用") + private String invalidMark; + + @Schema(description = "重复标识0已查重1有重复") + private Byte duplicateMark; + + @Schema(description = "验真0未验真1已验证") + private Byte checkTrue; + + @Schema(description = "加密") + private String encrypt; + + @Schema(description = "制单人") + private String createBy; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "归档id,一个归档id对应多个发票", example = "26489") + private Long recordId; + + @Schema(description = "业务实体id", example = "17678") + private Long companyId; + + @Schema(description = "业务实体") + private String company; + + @Schema(description = "所属部门id", example = "7722") + private Long deptId; + + @Schema(description = "所属部门", example = "赵六") + private String deptName; + + @Schema(description = "用户id", example = "12438") + private Long userId; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "预留字段1") + private String attr1; + + @Schema(description = "预留字段2") + private String attr2; + + @Schema(description = "预留字段3") + private Integer attr3; + + @Schema(description = "预留字段4") + private Integer attr4; + + @Schema(description = "归档状态") + private String archiveState; + + @Schema(description = "发票地址") + private String fileUrl; + +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesPageReqVO.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesPageReqVO.java new file mode 100644 index 00000000..eea59a1d --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesPageReqVO.java @@ -0,0 +1,211 @@ +package cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo; + +import lombok.*; +import java.util.*; +import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import org.springframework.format.annotation.DateTimeFormat; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 发票分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InvoicesPageReqVO extends PageParam { + + @Schema(description = "凭证id,一个凭证对应多个电子发票", example = "25675") + private Long voucherId; + + @Schema(description = "发票代码") + private String invoiceCode; + + @Schema(description = "发票号码") + private String invoiceNum; + + @Schema(description = "大写金额") + private String amountinWords; + + @Schema(description = "单价", example = "29904") + private String price; + + @Schema(description = "合计税额") + private String totalTax; + + @Schema(description = "税率") + private String taxRate; + + @Schema(description = "金额") + private String totalAmount; + + @Schema(description = "税额") + private String commodityTax; + + @Schema(description = "价税合计") + private String commodityAmount; + + @Schema(description = "小写价税合计") + private String amountinFiguers; + + @Schema(description = "开票人") + private String foteDrawer; + + @Schema(description = "销方地址电话") + private String sellerAddress; + + @Schema(description = "服务条数") + private String commodityNum; + + @Schema(description = "销方纳税识别号") + private String sellerRegisterNum; + + @Schema(description = "报送状态") + private String machineCode; + + @Schema(description = "备注") + private String remarks; + + @Schema(description = "销方开户行及账号") + private String sellerBank; + + @Schema(description = "校验码") + private String checkCode; + + @Schema(description = "开票日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] invoiceDate; + + @Schema(description = "购方税号") + private String purchaserRegisterNum; + + @Schema(description = "清单标志") + private String invoiceTypeOrg; + + @Schema(description = "密码区") + private String password; + + @Schema(description = "打印标志") + private String agent; + + @Schema(description = "购方开户行及账号") + private String purchaserBank; + + @Schema(description = "复核人") + private String checker; + + @Schema(description = "城市") + private String city; + + @Schema(description = "购方公司名", example = "芋艿") + private String purchaserName; + + @Schema(description = "规格型号", example = "1") + private String commodityType; + + @Schema(description = "报送日志") + private String province; + + @Schema(description = "发票种类", example = "1") + private String invoiceType; + + @Schema(description = "发票联") + private String sheetNum; + + @Schema(description = "购方地址电话") + private String purchaserAddress; + + @Schema(description = "部门") + private String commodityUnit; + + @Schema(description = "收款人") + private String payee; + + @Schema(description = "主要商品名称", example = "张三") + private String commodityName; + + @Schema(description = "销方名称", example = "王五") + private String sellerName; + + @Schema(description = "审核状态0待审核1已审核2审核退回3未提交") + private Byte invoiceCheck; + + @Schema(description = "是否印章0,1") + private Byte invoiceSeal; + + @Schema(description = "发票综合代码") + private String invoiceQrcode; + + @Schema(description = "发票综合号码") + private String invoiceQrnum; + + @Schema(description = "二维码查验(1查询相符,0查验不符)") + private Byte qrCheckCode; + + @Schema(description = "发票状态1正常0作废") + private Byte invoiceState; + + @Schema(description = "作废日期") + private LocalDateTime printNum; + + @Schema(description = "进销项标识0进项1销项") + private Byte inoutMark; + + @Schema(description = "作废标志0作废1启用") + private String invalidMark; + + @Schema(description = "重复标识0已查重1有重复") + private Byte duplicateMark; + + @Schema(description = "验真0未验真1已验证") + private Byte checkTrue; + + @Schema(description = "加密") + private String encrypt; + + @Schema(description = "制单人") + private String createBy; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + + @Schema(description = "归档id,一个归档id对应多个发票", example = "26489") + private Long recordId; + + @Schema(description = "业务实体id", example = "17678") + private Long companyId; + + @Schema(description = "业务实体") + private String company; + + @Schema(description = "所属部门id", example = "7722") + private Long deptId; + + @Schema(description = "所属部门", example = "赵六") + private String deptName; + + @Schema(description = "用户id", example = "12438") + private Long userId; + + @Schema(description = "备注", example = "随便") + private String remark; + + @Schema(description = "预留字段1") + private String attr1; + + @Schema(description = "预留字段2") + private String attr2; + + @Schema(description = "预留字段3") + private Integer attr3; + + @Schema(description = "预留字段4") + private Integer attr4; + + @Schema(description = "归档状态") + private String archiveState; + + @Schema(description = "发票地址") + private String fileUrl; +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesRespVO.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesRespVO.java new file mode 100644 index 00000000..b7cdc667 --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 发票 Response VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InvoicesRespVO extends InvoicesBaseVO { + + @Schema(description = "发票id", requiredMode = Schema.RequiredMode.REQUIRED, example = "5466") + private Long id; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesUpdateReqVO.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesUpdateReqVO.java new file mode 100644 index 00000000..8e7c2054 --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/invoices/vo/InvoicesUpdateReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import java.util.*; +import javax.validation.constraints.*; + +@Schema(description = "管理后台 - 发票更新 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class InvoicesUpdateReqVO extends InvoicesBaseVO { + + @Schema(description = "发票id", requiredMode = Schema.RequiredMode.REQUIRED, example = "5466") + @NotNull(message = "发票id不能为空") + private Long id; + +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/voucherdetails/vo/VoucherDetailsBaseVO.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/voucherdetails/vo/VoucherDetailsBaseVO.java index 296c6212..95375ce0 100644 --- a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/voucherdetails/vo/VoucherDetailsBaseVO.java +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/controller/admin/voucherdetails/vo/VoucherDetailsBaseVO.java @@ -45,7 +45,6 @@ public class VoucherDetailsBaseVO { private Long flowId; @Schema(description = "凭证id,一个凭证对应多个凭证详情", requiredMode = Schema.RequiredMode.REQUIRED, example = "31093") - @NotNull(message = "凭证id,一个凭证对应多个凭证详情不能为空") private Long voucherId; @Schema(description = "凭证号", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/convert/invoices/InvoicesConvert.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/convert/invoices/InvoicesConvert.java new file mode 100644 index 00000000..209189e5 --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/convert/invoices/InvoicesConvert.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.accounting.convert.invoices; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; +import cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo.*; +import cn.iocoder.yudao.module.accounting.dal.dataobject.invoices.InvoicesDO; + +/** + * 发票 Convert + * + * @author 芋道源码 + */ +@Mapper +public interface InvoicesConvert { + + InvoicesConvert INSTANCE = Mappers.getMapper(InvoicesConvert.class); + + InvoicesDO convert(InvoicesCreateReqVO bean); + + InvoicesDO convert(InvoicesUpdateReqVO bean); + + InvoicesRespVO convert(InvoicesDO bean); + + List convertList(List list); + + PageResult convertPage(PageResult page); + + List convertList02(List list); + +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/BaiduInvoicesDO.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/BaiduInvoicesDO.java new file mode 100644 index 00000000..ddbddde2 --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/BaiduInvoicesDO.java @@ -0,0 +1,147 @@ +package cn.iocoder.yudao.module.accounting.dal.dataobject.invoices; + +import lombok.*; + +import java.util.List; + +@Data +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BaiduInvoicesDO { + + private String log_id; + private int words_result_num; + private WordsResult words_result; + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class WordsResult { + private String InvoiceNumDigit; + private String ServiceType; + private String InvoiceNum; + private String InvoiceNumConfirm; + private String SellerName; + private List CommodityTaxRate; + private String SellerBank; + private String Checker; + private String TotalAmount; + private List CommodityAmount; + private String InvoiceDate; + private List CommodityTax; + private String PurchaserName; + private String CheckCode; + private List CommodityNum; + private String Province; + private String City; + private String SheetNum; + private String Agent; + private String PurchaserBank; + private String Remarks; + private String Password; + private String SellerAddress; + private String PurchaserAddress; + private String InvoiceCode; + private String InvoiceCodeConfirm; + private List CommodityUnit; + private String Payee; + private String PurchaserRegisterNum; + private List CommodityPrice; + private String NoteDrawer; + private String AmountInWords; + private String AmountInFiguers; + private String TotalTax; + private String InvoiceType; + private String SellerRegisterNum; + private List CommodityName; + private List CommodityType; + // Add other fields here... + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityTaxRate { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityAmount { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityTax { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityNum { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityUnit { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityPrice { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityName { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityType { + private String word; + private String row; + } + // Add other inner classes here... + } + // Getters, setters, and other utility methods... +} + diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/Converter.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/Converter.java new file mode 100644 index 00000000..eb061f50 --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/Converter.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.accounting.dal.dataobject.invoices; + +import cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo.InvoicesCreateReqVO; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class Converter { + + public static InvoicesCreateReqVO convertInvoiceToInvoicesDO(BaiduInvoicesDO invoice) { + if (invoice == null || invoice.getWords_result() == null) { + return null; // or throw an appropriate exception + } + + BaiduInvoicesDO.WordsResult wordsResult = invoice.getWords_result(); + InvoicesCreateReqVO invoicesDO = new InvoicesCreateReqVO(); + + invoicesDO.setInvoiceCode(wordsResult.getInvoiceCode()); + invoicesDO.setInvoiceNum(wordsResult.getInvoiceNum()); + invoicesDO.setTotalTax(wordsResult.getTotalTax()); + invoicesDO.setTotalAmount(wordsResult.getTotalAmount()); + invoicesDO.setAmountinWords(wordsResult.getAmountInWords()); + if (wordsResult.getCommodityTaxRate()!=null) { + if (wordsResult.getCommodityTaxRate().size()>0) { + invoicesDO.setTaxRate(wordsResult.getCommodityTaxRate().get(0).getWord()); + } + } + if (wordsResult.getCommodityTax()!=null) { + if (wordsResult.getCommodityTax().size()>0) { + invoicesDO.setCommodityTax(wordsResult.getCommodityTax().get(0).getWord()); + } + } + if (wordsResult.getCommodityAmount()!=null) { + if (wordsResult.getCommodityAmount().size()>0) { + invoicesDO.setCommodityAmount(wordsResult.getCommodityAmount().get(0).getWord()); + } + } + invoicesDO.setAmountinFiguers(wordsResult.getAmountInFiguers()); + invoicesDO.setFoteDrawer(wordsResult.getNoteDrawer()); + invoicesDO.setSellerAddress(wordsResult.getSellerAddress()); + invoicesDO.setSellerRegisterNum(wordsResult.getSellerRegisterNum()); + invoicesDO.setSellerName(wordsResult.getSellerName()); + invoicesDO.setSellerBank(wordsResult.getSellerBank()); + invoicesDO.setPurchaserAddress(wordsResult.getPurchaserAddress()); + invoicesDO.setPurchaserBank(wordsResult.getPurchaserBank()); + invoicesDO.setPurchaserName(wordsResult.getPurchaserName()); + invoicesDO.setPurchaserRegisterNum(wordsResult.getPurchaserRegisterNum()); + invoicesDO.setRemarks(wordsResult.getRemarks()); + invoicesDO.setSellerBank(wordsResult.getSellerBank()); + invoicesDO.setPassword(wordsResult.getPassword()); + invoicesDO.setChecker(wordsResult.getChecker()); + invoicesDO.setInvoiceType(wordsResult.getInvoiceType()); + invoicesDO.setPayee(wordsResult.getPayee()); + invoicesDO.setCheckCode(wordsResult.getCheckCode()); + // ... and so on for the rest ... + + // Example of a date conversion (assuming that the invoice date in Invoice is in String format) + String invoiceDateStr = wordsResult.getInvoiceDate().replace("年", "-").replace("月", "-").replace("日", "").trim(); + LocalDate parse = LocalDate.parse(invoiceDateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + LocalDateTime invoiceDate = parse.atStartOfDay();; + invoicesDO.setInvoiceDate(invoiceDate); + + // Handle other possible transformations or mappings here + + return invoicesDO; + } +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/InvoicesDO.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/InvoicesDO.java new file mode 100644 index 00000000..efe1af89 --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/InvoicesDO.java @@ -0,0 +1,286 @@ +package cn.iocoder.yudao.module.accounting.dal.dataobject.invoices; + +import lombok.*; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 发票 DO + * + * @author 芋道源码 + */ +@TableName("accounting_invoices") +@KeySequence("accounting_invoices_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class InvoicesDO extends BaseDO { + + /** + * 发票id + */ + @TableId + private Long id; + /** + * 凭证id,一个凭证对应多个电子发票 + */ + private Long voucherId; + /** + * 发票代码 + */ + private String invoiceCode; + /** + * 发票号码 + */ + private String invoiceNum; + /** + * 大写金额 + */ + private String amountinWords; + /** + * 单价 + */ + private String price; + /** + * 合计税额 + */ + private String totalTax; + /** + * 税率 + */ + private String taxRate; + /** + * 金额 + */ + private String totalAmount; + /** + * 税额 + */ + private String commodityTax; + /** + * 价税合计 + */ + private String commodityAmount; + /** + * 小写价税合计 + */ + private String amountinFiguers; + /** + * 开票人 + */ + private String foteDrawer; + /** + * 销方地址电话 + */ + private String sellerAddress; + /** + * 服务条数 + */ + private String commodityNum; + /** + * 销方纳税识别号 + */ + private String sellerRegisterNum; + /** + * 报送状态 + */ + private String machineCode; + /** + * 备注 + */ + private String remarks; + /** + * 销方开户行及账号 + */ + private String sellerBank; + /** + * 校验码 + */ + private String checkCode; + /** + * 开票日期 + */ + private LocalDateTime invoiceDate; + /** + * 购方税号 + */ + private String purchaserRegisterNum; + /** + * 清单标志 + */ + private String invoiceTypeOrg; + /** + * 密码区 + */ + private String password; + /** + * 打印标志 + */ + private String agent; + /** + * 购方开户行及账号 + */ + private String purchaserBank; + /** + * 复核人 + */ + private String checker; + /** + * 城市 + */ + private String city; + /** + * 购方公司名 + */ + private String purchaserName; + /** + * 规格型号 + */ + private String commodityType; + /** + * 报送日志 + */ + private String province; + /** + * 发票种类 + */ + private String invoiceType; + /** + * 发票联 + */ + private String sheetNum; + /** + * 购方地址电话 + */ + private String purchaserAddress; + /** + * 部门 + */ + private String commodityUnit; + /** + * 收款人 + */ + private String payee; + /** + * 主要商品名称 + */ + private String commodityName; + /** + * 销方名称 + */ + private String sellerName; + /** + * 审核状态0待审核1已审核2审核退回3未提交 + */ + private Byte invoiceCheck; + /** + * 是否印章0,1 + */ + private Byte invoiceSeal; + /** + * 发票综合代码 + */ + private String invoiceQrcode; + /** + * 发票综合号码 + */ + private String invoiceQrnum; + /** + * 二维码查验(1查询相符,0查验不符) + */ + private Byte qrCheckCode; + /** + * 发票状态1正常0作废 + */ + private Byte invoiceState; + /** + * 作废日期 + */ + private LocalDateTime printNum; + /** + * 进销项标识0进项1销项 + */ + private Byte inoutMark; + /** + * 作废标志0作废1启用 + */ + private String invalidMark; + /** + * 重复标识0已查重1有重复 + */ + private Byte duplicateMark; + /** + * 验真0未验真1已验证 + */ + private Byte checkTrue; + /** + * 加密 + */ + private String encrypt; + /** + * 制单人 + */ + private String createBy; + /** + * 归档id,一个归档id对应多个发票 + */ + private Long recordId; + /** + * 业务实体id + */ + private Long companyId; + /** + * 业务实体 + */ + private String company; + /** + * 所属部门id + */ + private Long deptId; + /** + * 所属部门 + */ + private String deptName; + /** + * 用户id + */ + private Long userId; + /** + * 备注 + */ + private String remark; + /** + * 预留字段1 + */ + private String attr1; + /** + * 预留字段2 + */ + private String attr2; + /** + * 预留字段3 + */ + private Integer attr3; + /** + * 预留字段4 + */ + private Integer attr4; + /** + * 归档状态 + */ + private String archiveState; + + /** + * 发票地址 + */ + private String fileUrl; + +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/invoiceVerification.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/invoiceVerification.java new file mode 100644 index 00000000..a70da251 --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/dataobject/invoices/invoiceVerification.java @@ -0,0 +1,313 @@ +package cn.iocoder.yudao.module.accounting.dal.dataobject.invoices; + +import lombok.*; + +import java.util.List; + +/** + * 增值税发票验真实体类 + */ + +@Data +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class invoiceVerification { + private String log_id; + private int words_result_num; + private String VerifyFrequency; + private String VerifyMessage; + private String InvalidSign; + private String InvoiceType; + private String MachineCode; + private String CheckCode; + private String InvoiceCode; + private String InvoiceDate; + private String VerifyResult; + private String InvoiceNum; + private String TaxControlNum; + private List CommodityEndDate; + private String VehicleTonnage; + private List CommodityVehicleType; + private List CommodityStartDate; + private String SellerAddress; + private List CommodityPrice; + private String TransportCargoInformation; + private String NoteDrawer; + private List CommodityNum; + private String SellerRegisterNum; + private String SellerBank; + private String Remarks; + private String TotalTax; + private List CommodityTaxRate; + private List CommodityExpenseItem; + private String ZeroTaxRateIndicator; + private String Carrier; + private String SenderCode; + private String PurchaserRegisterNum; + private String ReceiverCode; + private String AmountInFiguers; + private String PurchaserBank; + private String Checker; + private String TollSign; + private String VehicleTypeNum; + private String DepartureViaArrival; + private String Receiver; + private String Recipient; + private String TotalAmount; + private List CommodityAmount; + private String PurchaserName; + private List CommodityType; + private String Sender; + private String PurchaserAddress; + private List CommodityTax; + private String CarrierCode; + private List CommodityPlateNum; + private List CommodityUnit; + private String Payee; + private String RecipientCode; + private List CommodityName; + private String SellerName; + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityTax { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityNum { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityUnit { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityPrice { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityName { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityType { + private String word; + private String row; + } + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityAmount { + private String word; + private String row; + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityEndDate { + private String row; + private String word; + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityVehicleType { + private String row; + + // Getters and setters omitted for brevity + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityStartDate { + private String row; + private String word; + + // Getters and setters omitted for brevity + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityPrice { + private String row; + private String word; + + // Getters and setters omitted for brevity + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityNum { + private String row; + private String word; + + // Getters and setters omitted for brevity + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityTaxRate { + private String row; + private String word; + + // Getters and setters omitted for brevity + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityExpenseItem { + private String row; + private String word; + + // Getters and setters omitted for brevity + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityAmount { + private String row; + private String word; + + // Getters and setters omitted for brevity + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityType { + private String row; + private String word; + + // Getters and setters omitted for brevity + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityTax { + private String row; + private String word; + + // Getters and setters omitted for brevity + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityPlateNum { + private String row; + private String word; + + // Getters and setters omitted for brevity + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityUnit { + private String row; + private String word; + + // Getters and setters omitted for brevity + } + + + @Data + @ToString(callSuper = true) + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class CommodityName { + private String row; + private String word; + + // Getters and setters omitted for brevity + } + // Getters and setters omitted for brevity + } + // Getters and setters omitted for brevity +} + + diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/mysql/invoices/InvoicesMapper.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/mysql/invoices/InvoicesMapper.java new file mode 100644 index 00000000..3b79cb2c --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/dal/mysql/invoices/InvoicesMapper.java @@ -0,0 +1,156 @@ +package cn.iocoder.yudao.module.accounting.dal.mysql.invoices; + +import java.util.*; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.accounting.dal.dataobject.invoices.InvoicesDO; +import org.apache.ibatis.annotations.Mapper; +import cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo.*; + +/** + * 发票 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface InvoicesMapper extends BaseMapperX { + + default PageResult selectPage(InvoicesPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(InvoicesDO::getVoucherId, reqVO.getVoucherId()) + .eqIfPresent(InvoicesDO::getInvoiceCode, reqVO.getInvoiceCode()) + .eqIfPresent(InvoicesDO::getInvoiceNum, reqVO.getInvoiceNum()) + .eqIfPresent(InvoicesDO::getAmountinWords, reqVO.getAmountinWords()) + .eqIfPresent(InvoicesDO::getPrice, reqVO.getPrice()) + .eqIfPresent(InvoicesDO::getTotalTax, reqVO.getTotalTax()) + .eqIfPresent(InvoicesDO::getTaxRate, reqVO.getTaxRate()) + .eqIfPresent(InvoicesDO::getTotalAmount, reqVO.getTotalAmount()) + .eqIfPresent(InvoicesDO::getCommodityTax, reqVO.getCommodityTax()) + .eqIfPresent(InvoicesDO::getCommodityAmount, reqVO.getCommodityAmount()) + .eqIfPresent(InvoicesDO::getAmountinFiguers, reqVO.getAmountinFiguers()) + .eqIfPresent(InvoicesDO::getFoteDrawer, reqVO.getFoteDrawer()) + .eqIfPresent(InvoicesDO::getSellerAddress, reqVO.getSellerAddress()) + .eqIfPresent(InvoicesDO::getCommodityNum, reqVO.getCommodityNum()) + .eqIfPresent(InvoicesDO::getSellerRegisterNum, reqVO.getSellerRegisterNum()) + .eqIfPresent(InvoicesDO::getMachineCode, reqVO.getMachineCode()) + .eqIfPresent(InvoicesDO::getRemarks, reqVO.getRemarks()) + .eqIfPresent(InvoicesDO::getSellerBank, reqVO.getSellerBank()) + .eqIfPresent(InvoicesDO::getCheckCode, reqVO.getCheckCode()) + .betweenIfPresent(InvoicesDO::getInvoiceDate, reqVO.getInvoiceDate()) + .eqIfPresent(InvoicesDO::getPurchaserRegisterNum, reqVO.getPurchaserRegisterNum()) + .eqIfPresent(InvoicesDO::getInvoiceTypeOrg, reqVO.getInvoiceTypeOrg()) + .eqIfPresent(InvoicesDO::getPassword, reqVO.getPassword()) + .eqIfPresent(InvoicesDO::getAgent, reqVO.getAgent()) + .eqIfPresent(InvoicesDO::getPurchaserBank, reqVO.getPurchaserBank()) + .eqIfPresent(InvoicesDO::getChecker, reqVO.getChecker()) + .eqIfPresent(InvoicesDO::getCity, reqVO.getCity()) + .likeIfPresent(InvoicesDO::getPurchaserName, reqVO.getPurchaserName()) + .eqIfPresent(InvoicesDO::getCommodityType, reqVO.getCommodityType()) + .eqIfPresent(InvoicesDO::getProvince, reqVO.getProvince()) + .eqIfPresent(InvoicesDO::getInvoiceType, reqVO.getInvoiceType()) + .eqIfPresent(InvoicesDO::getSheetNum, reqVO.getSheetNum()) + .eqIfPresent(InvoicesDO::getPurchaserAddress, reqVO.getPurchaserAddress()) + .eqIfPresent(InvoicesDO::getCommodityUnit, reqVO.getCommodityUnit()) + .eqIfPresent(InvoicesDO::getPayee, reqVO.getPayee()) + .likeIfPresent(InvoicesDO::getCommodityName, reqVO.getCommodityName()) + .likeIfPresent(InvoicesDO::getSellerName, reqVO.getSellerName()) + .eqIfPresent(InvoicesDO::getInvoiceCheck, reqVO.getInvoiceCheck()) + .eqIfPresent(InvoicesDO::getInvoiceSeal, reqVO.getInvoiceSeal()) + .eqIfPresent(InvoicesDO::getInvoiceQrcode, reqVO.getInvoiceQrcode()) + .eqIfPresent(InvoicesDO::getInvoiceQrnum, reqVO.getInvoiceQrnum()) + .eqIfPresent(InvoicesDO::getQrCheckCode, reqVO.getQrCheckCode()) + .eqIfPresent(InvoicesDO::getInvoiceState, reqVO.getInvoiceState()) + .eqIfPresent(InvoicesDO::getPrintNum, reqVO.getPrintNum()) + .eqIfPresent(InvoicesDO::getInoutMark, reqVO.getInoutMark()) + .eqIfPresent(InvoicesDO::getInvalidMark, reqVO.getInvalidMark()) + .eqIfPresent(InvoicesDO::getDuplicateMark, reqVO.getDuplicateMark()) + .eqIfPresent(InvoicesDO::getCheckTrue, reqVO.getCheckTrue()) + .eqIfPresent(InvoicesDO::getEncrypt, reqVO.getEncrypt()) + .eqIfPresent(InvoicesDO::getCreateBy, reqVO.getCreateBy()) + .betweenIfPresent(InvoicesDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(InvoicesDO::getRecordId, reqVO.getRecordId()) + .eqIfPresent(InvoicesDO::getCompanyId, reqVO.getCompanyId()) + .eqIfPresent(InvoicesDO::getCompany, reqVO.getCompany()) + .eqIfPresent(InvoicesDO::getDeptId, reqVO.getDeptId()) + .likeIfPresent(InvoicesDO::getDeptName, reqVO.getDeptName()) + .eqIfPresent(InvoicesDO::getUserId, reqVO.getUserId()) + .eqIfPresent(InvoicesDO::getRemark, reqVO.getRemark()) + .eqIfPresent(InvoicesDO::getAttr1, reqVO.getAttr1()) + .eqIfPresent(InvoicesDO::getAttr2, reqVO.getAttr2()) + .eqIfPresent(InvoicesDO::getAttr3, reqVO.getAttr3()) + .eqIfPresent(InvoicesDO::getAttr4, reqVO.getAttr4()) + .eqIfPresent(InvoicesDO::getArchiveState, reqVO.getArchiveState()) + .orderByDesc(InvoicesDO::getId)); + } + + default List selectList(InvoicesExportReqVO reqVO) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(InvoicesDO::getVoucherId, reqVO.getVoucherId()) + .eqIfPresent(InvoicesDO::getInvoiceCode, reqVO.getInvoiceCode()) + .eqIfPresent(InvoicesDO::getInvoiceNum, reqVO.getInvoiceNum()) + .eqIfPresent(InvoicesDO::getAmountinWords, reqVO.getAmountinWords()) + .eqIfPresent(InvoicesDO::getPrice, reqVO.getPrice()) + .eqIfPresent(InvoicesDO::getTotalTax, reqVO.getTotalTax()) + .eqIfPresent(InvoicesDO::getTaxRate, reqVO.getTaxRate()) + .eqIfPresent(InvoicesDO::getTotalAmount, reqVO.getTotalAmount()) + .eqIfPresent(InvoicesDO::getCommodityTax, reqVO.getCommodityTax()) + .eqIfPresent(InvoicesDO::getCommodityAmount, reqVO.getCommodityAmount()) + .eqIfPresent(InvoicesDO::getAmountinFiguers, reqVO.getAmountinFiguers()) + .eqIfPresent(InvoicesDO::getFoteDrawer, reqVO.getFoteDrawer()) + .eqIfPresent(InvoicesDO::getSellerAddress, reqVO.getSellerAddress()) + .eqIfPresent(InvoicesDO::getCommodityNum, reqVO.getCommodityNum()) + .eqIfPresent(InvoicesDO::getSellerRegisterNum, reqVO.getSellerRegisterNum()) + .eqIfPresent(InvoicesDO::getMachineCode, reqVO.getMachineCode()) + .eqIfPresent(InvoicesDO::getRemarks, reqVO.getRemarks()) + .eqIfPresent(InvoicesDO::getSellerBank, reqVO.getSellerBank()) + .eqIfPresent(InvoicesDO::getCheckCode, reqVO.getCheckCode()) + .betweenIfPresent(InvoicesDO::getInvoiceDate, reqVO.getInvoiceDate()) + .eqIfPresent(InvoicesDO::getPurchaserRegisterNum, reqVO.getPurchaserRegisterNum()) + .eqIfPresent(InvoicesDO::getInvoiceTypeOrg, reqVO.getInvoiceTypeOrg()) + .eqIfPresent(InvoicesDO::getPassword, reqVO.getPassword()) + .eqIfPresent(InvoicesDO::getAgent, reqVO.getAgent()) + .eqIfPresent(InvoicesDO::getPurchaserBank, reqVO.getPurchaserBank()) + .eqIfPresent(InvoicesDO::getChecker, reqVO.getChecker()) + .eqIfPresent(InvoicesDO::getCity, reqVO.getCity()) + .likeIfPresent(InvoicesDO::getPurchaserName, reqVO.getPurchaserName()) + .eqIfPresent(InvoicesDO::getCommodityType, reqVO.getCommodityType()) + .eqIfPresent(InvoicesDO::getProvince, reqVO.getProvince()) + .eqIfPresent(InvoicesDO::getInvoiceType, reqVO.getInvoiceType()) + .eqIfPresent(InvoicesDO::getSheetNum, reqVO.getSheetNum()) + .eqIfPresent(InvoicesDO::getPurchaserAddress, reqVO.getPurchaserAddress()) + .eqIfPresent(InvoicesDO::getCommodityUnit, reqVO.getCommodityUnit()) + .eqIfPresent(InvoicesDO::getPayee, reqVO.getPayee()) + .likeIfPresent(InvoicesDO::getCommodityName, reqVO.getCommodityName()) + .likeIfPresent(InvoicesDO::getSellerName, reqVO.getSellerName()) + .eqIfPresent(InvoicesDO::getInvoiceCheck, reqVO.getInvoiceCheck()) + .eqIfPresent(InvoicesDO::getInvoiceSeal, reqVO.getInvoiceSeal()) + .eqIfPresent(InvoicesDO::getInvoiceQrcode, reqVO.getInvoiceQrcode()) + .eqIfPresent(InvoicesDO::getInvoiceQrnum, reqVO.getInvoiceQrnum()) + .eqIfPresent(InvoicesDO::getQrCheckCode, reqVO.getQrCheckCode()) + .eqIfPresent(InvoicesDO::getInvoiceState, reqVO.getInvoiceState()) + .eqIfPresent(InvoicesDO::getPrintNum, reqVO.getPrintNum()) + .eqIfPresent(InvoicesDO::getInoutMark, reqVO.getInoutMark()) + .eqIfPresent(InvoicesDO::getInvalidMark, reqVO.getInvalidMark()) + .eqIfPresent(InvoicesDO::getDuplicateMark, reqVO.getDuplicateMark()) + .eqIfPresent(InvoicesDO::getCheckTrue, reqVO.getCheckTrue()) + .eqIfPresent(InvoicesDO::getEncrypt, reqVO.getEncrypt()) + .eqIfPresent(InvoicesDO::getCreateBy, reqVO.getCreateBy()) + .betweenIfPresent(InvoicesDO::getCreateTime, reqVO.getCreateTime()) + .eqIfPresent(InvoicesDO::getRecordId, reqVO.getRecordId()) + .eqIfPresent(InvoicesDO::getCompanyId, reqVO.getCompanyId()) + .eqIfPresent(InvoicesDO::getCompany, reqVO.getCompany()) + .eqIfPresent(InvoicesDO::getDeptId, reqVO.getDeptId()) + .likeIfPresent(InvoicesDO::getDeptName, reqVO.getDeptName()) + .eqIfPresent(InvoicesDO::getUserId, reqVO.getUserId()) + .eqIfPresent(InvoicesDO::getRemark, reqVO.getRemark()) + .eqIfPresent(InvoicesDO::getAttr1, reqVO.getAttr1()) + .eqIfPresent(InvoicesDO::getAttr2, reqVO.getAttr2()) + .eqIfPresent(InvoicesDO::getAttr3, reqVO.getAttr3()) + .eqIfPresent(InvoicesDO::getAttr4, reqVO.getAttr4()) + .eqIfPresent(InvoicesDO::getArchiveState, reqVO.getArchiveState()) + .orderByDesc(InvoicesDO::getId)); + } + +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesService.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesService.java new file mode 100644 index 00000000..02a7e266 --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesService.java @@ -0,0 +1,70 @@ +package cn.iocoder.yudao.module.accounting.service.invoices; + +import java.util.*; +import javax.validation.*; +import cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo.*; +import cn.iocoder.yudao.module.accounting.dal.dataobject.invoices.InvoicesDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +/** + * 发票 Service 接口 + * + * @author 芋道源码 + */ +public interface InvoicesService { + + /** + * 创建发票 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createInvoices(@Valid InvoicesCreateReqVO createReqVO); + + /** + * 更新发票 + * + * @param updateReqVO 更新信息 + */ + void updateInvoices(@Valid InvoicesUpdateReqVO updateReqVO); + + /** + * 删除发票 + * + * @param id 编号 + */ + void deleteInvoices(Long id); + + /** + * 获得发票 + * + * @param id 编号 + * @return 发票 + */ + InvoicesDO getInvoices(Long id); + + /** + * 获得发票列表 + * + * @param ids 编号 + * @return 发票列表 + */ + List getInvoicesList(Collection ids); + + /** + * 获得发票分页 + * + * @param pageReqVO 分页查询 + * @return 发票分页 + */ + PageResult getInvoicesPage(InvoicesPageReqVO pageReqVO); + + /** + * 获得发票列表, 用于 Excel 导出 + * + * @param exportReqVO 查询条件 + * @return 发票列表 + */ + List getInvoicesList(InvoicesExportReqVO exportReqVO); + +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesServiceImpl.java b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesServiceImpl.java new file mode 100644 index 00000000..c50209dc --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesServiceImpl.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.accounting.service.invoices; + +import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import org.springframework.validation.annotation.Validated; + +import java.util.*; +import cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo.*; +import cn.iocoder.yudao.module.accounting.dal.dataobject.invoices.InvoicesDO; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import cn.iocoder.yudao.module.accounting.convert.invoices.InvoicesConvert; +import cn.iocoder.yudao.module.accounting.dal.mysql.invoices.InvoicesMapper; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.accounting.enums.ErrorCodeConstants.*; + +/** + * 发票 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class InvoicesServiceImpl implements InvoicesService { + + @Resource + private InvoicesMapper invoicesMapper; + + @Override + public Long createInvoices(InvoicesCreateReqVO createReqVO) { + // 插入 + InvoicesDO invoices = InvoicesConvert.INSTANCE.convert(createReqVO); + invoicesMapper.insert(invoices); + // 返回 + return invoices.getId(); + } + + @Override + public void updateInvoices(InvoicesUpdateReqVO updateReqVO) { + // 校验存在 + validateInvoicesExists(updateReqVO.getId()); + // 更新 + InvoicesDO updateObj = InvoicesConvert.INSTANCE.convert(updateReqVO); + invoicesMapper.updateById(updateObj); + } + + @Override + public void deleteInvoices(Long id) { + // 校验存在 + validateInvoicesExists(id); + // 删除 + invoicesMapper.deleteById(id); + } + + private void validateInvoicesExists(Long id) { + if (invoicesMapper.selectById(id) == null) { + throw exception(INVOICES_NOT_EXISTS); + } + } + + @Override + public InvoicesDO getInvoices(Long id) { + return invoicesMapper.selectById(id); + } + + @Override + public List getInvoicesList(Collection ids) { + return invoicesMapper.selectBatchIds(ids); + } + + @Override + public PageResult getInvoicesPage(InvoicesPageReqVO pageReqVO) { + return invoicesMapper.selectPage(pageReqVO); + } + + @Override + public List getInvoicesList(InvoicesExportReqVO exportReqVO) { + return invoicesMapper.selectList(exportReqVO); + } + +} diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/main/resources/mapper/invoices/InvoicesMapper.xml b/yudao-module-accounting/yudao-module-accounting-biz/src/main/resources/mapper/invoices/InvoicesMapper.xml new file mode 100644 index 00000000..24a476f2 --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/main/resources/mapper/invoices/InvoicesMapper.xml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/yudao-module-accounting/yudao-module-accounting-biz/src/test/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesServiceImplTest.java b/yudao-module-accounting/yudao-module-accounting-biz/src/test/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesServiceImplTest.java new file mode 100644 index 00000000..054bca0c --- /dev/null +++ b/yudao-module-accounting/yudao-module-accounting-biz/src/test/java/cn/iocoder/yudao/module/accounting/service/invoices/InvoicesServiceImplTest.java @@ -0,0 +1,647 @@ +package cn.iocoder.yudao.module.accounting.service.invoices; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.mock.mockito.MockBean; + +import javax.annotation.Resource; + +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; + +import cn.iocoder.yudao.module.accounting.controller.admin.invoices.vo.*; +import cn.iocoder.yudao.module.accounting.dal.dataobject.invoices.InvoicesDO; +import cn.iocoder.yudao.module.accounting.dal.mysql.invoices.InvoicesMapper; +import cn.iocoder.yudao.framework.common.pojo.PageResult; + +import javax.annotation.Resource; +import org.springframework.context.annotation.Import; +import java.util.*; +import java.time.LocalDateTime; + +import static cn.hutool.core.util.RandomUtil.*; +import static cn.iocoder.yudao.module.accounting.enums.ErrorCodeConstants.*; +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.*; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*; +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.*; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +/** + * {@link InvoicesServiceImpl} 的单元测试类 + * + * @author 芋道源码 + */ +@Import(InvoicesServiceImpl.class) +public class InvoicesServiceImplTest extends BaseDbUnitTest { + + @Resource + private InvoicesServiceImpl invoicesService; + + @Resource + private InvoicesMapper invoicesMapper; + + @Test + public void testCreateInvoices_success() { + // 准备参数 + InvoicesCreateReqVO reqVO = randomPojo(InvoicesCreateReqVO.class); + + // 调用 + Long invoicesId = invoicesService.createInvoices(reqVO); + // 断言 + assertNotNull(invoicesId); + // 校验记录的属性是否正确 + InvoicesDO invoices = invoicesMapper.selectById(invoicesId); + assertPojoEquals(reqVO, invoices); + } + + @Test + public void testUpdateInvoices_success() { + // mock 数据 + InvoicesDO dbInvoices = randomPojo(InvoicesDO.class); + invoicesMapper.insert(dbInvoices);// @Sql: 先插入出一条存在的数据 + // 准备参数 + InvoicesUpdateReqVO reqVO = randomPojo(InvoicesUpdateReqVO.class, o -> { + o.setId(dbInvoices.getId()); // 设置更新的 ID + }); + + // 调用 + invoicesService.updateInvoices(reqVO); + // 校验是否更新正确 + InvoicesDO invoices = invoicesMapper.selectById(reqVO.getId()); // 获取最新的 + assertPojoEquals(reqVO, invoices); + } + + @Test + public void testUpdateInvoices_notExists() { + // 准备参数 + InvoicesUpdateReqVO reqVO = randomPojo(InvoicesUpdateReqVO.class); + + // 调用, 并断言异常 + assertServiceException(() -> invoicesService.updateInvoices(reqVO), INVOICES_NOT_EXISTS); + } + + @Test + public void testDeleteInvoices_success() { + // mock 数据 + InvoicesDO dbInvoices = randomPojo(InvoicesDO.class); + invoicesMapper.insert(dbInvoices);// @Sql: 先插入出一条存在的数据 + // 准备参数 + Long id = dbInvoices.getId(); + + // 调用 + invoicesService.deleteInvoices(id); + // 校验数据不存在了 + assertNull(invoicesMapper.selectById(id)); + } + + @Test + public void testDeleteInvoices_notExists() { + // 准备参数 + Long id = randomLongId(); + + // 调用, 并断言异常 + assertServiceException(() -> invoicesService.deleteInvoices(id), INVOICES_NOT_EXISTS); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetInvoicesPage() { + // mock 数据 + InvoicesDO dbInvoices = randomPojo(InvoicesDO.class, o -> { // 等会查询到 + o.setVoucherId(null); + o.setInvoiceCode(null); + o.setInvoiceNum(null); + o.setAmountinWords(null); + o.setPrice(null); + o.setTotalTax(null); + o.setTaxRate(null); + o.setTotalAmount(null); + o.setCommodityTax(null); + o.setCommodityAmount(null); + o.setAmountinFiguers(null); + o.setFoteDrawer(null); + o.setSellerAddress(null); + o.setCommodityNum(null); + o.setSellerRegisterNum(null); + o.setMachineCode(null); + o.setRemarks(null); + o.setSellerBank(null); + o.setCheckCode(null); + o.setInvoiceDate(null); + o.setPurchaserRegisterNum(null); + o.setInvoiceTypeOrg(null); + o.setPassword(null); + o.setAgent(null); + o.setPurchaserBank(null); + o.setChecker(null); + o.setCity(null); + o.setPurchaserName(null); + o.setCommodityType(null); + o.setProvince(null); + o.setInvoiceType(null); + o.setSheetNum(null); + o.setPurchaserAddress(null); + o.setCommodityUnit(null); + o.setPayee(null); + o.setCommodityName(null); + o.setSellerName(null); + o.setInvoiceCheck(null); + o.setInvoiceSeal(null); + o.setInvoiceQrcode(null); + o.setInvoiceQrnum(null); + o.setQrCheckCode(null); + o.setInvoiceState(null); + o.setPrintNum(null); + o.setInoutMark(null); + o.setInvalidMark(null); + o.setDuplicateMark(null); + o.setCheckTrue(null); + o.setEncrypt(null); + o.setCreateBy(null); + o.setCreateTime(null); + o.setRecordId(null); + o.setCompanyId(null); + o.setCompany(null); + o.setDeptId(null); + o.setDeptName(null); + o.setUserId(null); + o.setRemark(null); + o.setAttr1(null); + o.setAttr2(null); + o.setAttr3(null); + o.setAttr4(null); + o.setArchiveState(null); + }); + invoicesMapper.insert(dbInvoices); + // 测试 voucherId 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setVoucherId(null))); + // 测试 invoiceCode 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceCode(null))); + // 测试 invoiceNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceNum(null))); + // 测试 amountinWords 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAmountinWords(null))); + // 测试 price 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPrice(null))); + // 测试 totalTax 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setTotalTax(null))); + // 测试 taxRate 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setTaxRate(null))); + // 测试 totalAmount 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setTotalAmount(null))); + // 测试 commodityTax 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityTax(null))); + // 测试 commodityAmount 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityAmount(null))); + // 测试 amountinFiguers 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAmountinFiguers(null))); + // 测试 foteDrawer 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setFoteDrawer(null))); + // 测试 sellerAddress 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setSellerAddress(null))); + // 测试 commodityNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityNum(null))); + // 测试 sellerRegisterNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setSellerRegisterNum(null))); + // 测试 machineCode 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setMachineCode(null))); + // 测试 remarks 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setRemarks(null))); + // 测试 sellerBank 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setSellerBank(null))); + // 测试 checkCode 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCheckCode(null))); + // 测试 invoiceDate 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceDate(null))); + // 测试 purchaserRegisterNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPurchaserRegisterNum(null))); + // 测试 invoiceTypeOrg 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceTypeOrg(null))); + // 测试 password 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPassword(null))); + // 测试 agent 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAgent(null))); + // 测试 purchaserBank 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPurchaserBank(null))); + // 测试 checker 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setChecker(null))); + // 测试 city 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCity(null))); + // 测试 purchaserName 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPurchaserName(null))); + // 测试 commodityType 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityType(null))); + // 测试 province 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setProvince(null))); + // 测试 invoiceType 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceType(null))); + // 测试 sheetNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setSheetNum(null))); + // 测试 purchaserAddress 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPurchaserAddress(null))); + // 测试 commodityUnit 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityUnit(null))); + // 测试 payee 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPayee(null))); + // 测试 commodityName 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityName(null))); + // 测试 sellerName 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setSellerName(null))); + // 测试 invoiceCheck 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceCheck(null))); + // 测试 invoiceSeal 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceSeal(null))); + // 测试 invoiceQrcode 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceQrcode(null))); + // 测试 invoiceQrnum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceQrnum(null))); + // 测试 qrCheckCode 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setQrCheckCode(null))); + // 测试 invoiceState 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceState(null))); + // 测试 printNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPrintNum(null))); + // 测试 inoutMark 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInoutMark(null))); + // 测试 invalidMark 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvalidMark(null))); + // 测试 duplicateMark 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setDuplicateMark(null))); + // 测试 checkTrue 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCheckTrue(null))); + // 测试 encrypt 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setEncrypt(null))); + // 测试 createBy 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCreateBy(null))); + // 测试 createTime 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCreateTime(null))); + // 测试 recordId 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setRecordId(null))); + // 测试 companyId 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCompanyId(null))); + // 测试 company 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCompany(null))); + // 测试 deptId 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setDeptId(null))); + // 测试 deptName 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setDeptName(null))); + // 测试 userId 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setUserId(null))); + // 测试 remark 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setRemark(null))); + // 测试 attr1 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAttr1(null))); + // 测试 attr2 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAttr2(null))); + // 测试 attr3 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAttr3(null))); + // 测试 attr4 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAttr4(null))); + // 测试 archiveState 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setArchiveState(null))); + // 准备参数 + InvoicesPageReqVO reqVO = new InvoicesPageReqVO(); + reqVO.setVoucherId(null); + reqVO.setInvoiceCode(null); + reqVO.setInvoiceNum(null); + reqVO.setAmountinWords(null); + reqVO.setPrice(null); + reqVO.setTotalTax(null); + reqVO.setTaxRate(null); + reqVO.setTotalAmount(null); + reqVO.setCommodityTax(null); + reqVO.setCommodityAmount(null); + reqVO.setAmountinFiguers(null); + reqVO.setFoteDrawer(null); + reqVO.setSellerAddress(null); + reqVO.setCommodityNum(null); + reqVO.setSellerRegisterNum(null); + reqVO.setMachineCode(null); + reqVO.setRemarks(null); + reqVO.setSellerBank(null); + reqVO.setCheckCode(null); + reqVO.setInvoiceDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setPurchaserRegisterNum(null); + reqVO.setInvoiceTypeOrg(null); + reqVO.setPassword(null); + reqVO.setAgent(null); + reqVO.setPurchaserBank(null); + reqVO.setChecker(null); + reqVO.setCity(null); + reqVO.setPurchaserName(null); + reqVO.setCommodityType(null); + reqVO.setProvince(null); + reqVO.setInvoiceType(null); + reqVO.setSheetNum(null); + reqVO.setPurchaserAddress(null); + reqVO.setCommodityUnit(null); + reqVO.setPayee(null); + reqVO.setCommodityName(null); + reqVO.setSellerName(null); + reqVO.setInvoiceCheck(null); + reqVO.setInvoiceSeal(null); + reqVO.setInvoiceQrcode(null); + reqVO.setInvoiceQrnum(null); + reqVO.setQrCheckCode(null); + reqVO.setInvoiceState(null); + reqVO.setPrintNum(null); + reqVO.setInoutMark(null); + reqVO.setInvalidMark(null); + reqVO.setDuplicateMark(null); + reqVO.setCheckTrue(null); + reqVO.setEncrypt(null); + reqVO.setCreateBy(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setRecordId(null); + reqVO.setCompanyId(null); + reqVO.setCompany(null); + reqVO.setDeptId(null); + reqVO.setDeptName(null); + reqVO.setUserId(null); + reqVO.setRemark(null); + reqVO.setAttr1(null); + reqVO.setAttr2(null); + reqVO.setAttr3(null); + reqVO.setAttr4(null); + reqVO.setArchiveState(null); + + // 调用 + PageResult pageResult = invoicesService.getInvoicesPage(reqVO); + // 断言 + assertEquals(1, pageResult.getTotal()); + assertEquals(1, pageResult.getList().size()); + assertPojoEquals(dbInvoices, pageResult.getList().get(0)); + } + + @Test + @Disabled // TODO 请修改 null 为需要的值,然后删除 @Disabled 注解 + public void testGetInvoicesList() { + // mock 数据 + InvoicesDO dbInvoices = randomPojo(InvoicesDO.class, o -> { // 等会查询到 + o.setVoucherId(null); + o.setInvoiceCode(null); + o.setInvoiceNum(null); + o.setAmountinWords(null); + o.setPrice(null); + o.setTotalTax(null); + o.setTaxRate(null); + o.setTotalAmount(null); + o.setCommodityTax(null); + o.setCommodityAmount(null); + o.setAmountinFiguers(null); + o.setFoteDrawer(null); + o.setSellerAddress(null); + o.setCommodityNum(null); + o.setSellerRegisterNum(null); + o.setMachineCode(null); + o.setRemarks(null); + o.setSellerBank(null); + o.setCheckCode(null); + o.setInvoiceDate(null); + o.setPurchaserRegisterNum(null); + o.setInvoiceTypeOrg(null); + o.setPassword(null); + o.setAgent(null); + o.setPurchaserBank(null); + o.setChecker(null); + o.setCity(null); + o.setPurchaserName(null); + o.setCommodityType(null); + o.setProvince(null); + o.setInvoiceType(null); + o.setSheetNum(null); + o.setPurchaserAddress(null); + o.setCommodityUnit(null); + o.setPayee(null); + o.setCommodityName(null); + o.setSellerName(null); + o.setInvoiceCheck(null); + o.setInvoiceSeal(null); + o.setInvoiceQrcode(null); + o.setInvoiceQrnum(null); + o.setQrCheckCode(null); + o.setInvoiceState(null); + o.setPrintNum(null); + o.setInoutMark(null); + o.setInvalidMark(null); + o.setDuplicateMark(null); + o.setCheckTrue(null); + o.setEncrypt(null); + o.setCreateBy(null); + o.setCreateTime(null); + o.setRecordId(null); + o.setCompanyId(null); + o.setCompany(null); + o.setDeptId(null); + o.setDeptName(null); + o.setUserId(null); + o.setRemark(null); + o.setAttr1(null); + o.setAttr2(null); + o.setAttr3(null); + o.setAttr4(null); + o.setArchiveState(null); + }); + invoicesMapper.insert(dbInvoices); + // 测试 voucherId 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setVoucherId(null))); + // 测试 invoiceCode 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceCode(null))); + // 测试 invoiceNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceNum(null))); + // 测试 amountinWords 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAmountinWords(null))); + // 测试 price 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPrice(null))); + // 测试 totalTax 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setTotalTax(null))); + // 测试 taxRate 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setTaxRate(null))); + // 测试 totalAmount 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setTotalAmount(null))); + // 测试 commodityTax 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityTax(null))); + // 测试 commodityAmount 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityAmount(null))); + // 测试 amountinFiguers 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAmountinFiguers(null))); + // 测试 foteDrawer 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setFoteDrawer(null))); + // 测试 sellerAddress 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setSellerAddress(null))); + // 测试 commodityNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityNum(null))); + // 测试 sellerRegisterNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setSellerRegisterNum(null))); + // 测试 machineCode 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setMachineCode(null))); + // 测试 remarks 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setRemarks(null))); + // 测试 sellerBank 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setSellerBank(null))); + // 测试 checkCode 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCheckCode(null))); + // 测试 invoiceDate 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceDate(null))); + // 测试 purchaserRegisterNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPurchaserRegisterNum(null))); + // 测试 invoiceTypeOrg 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceTypeOrg(null))); + // 测试 password 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPassword(null))); + // 测试 agent 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAgent(null))); + // 测试 purchaserBank 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPurchaserBank(null))); + // 测试 checker 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setChecker(null))); + // 测试 city 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCity(null))); + // 测试 purchaserName 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPurchaserName(null))); + // 测试 commodityType 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityType(null))); + // 测试 province 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setProvince(null))); + // 测试 invoiceType 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceType(null))); + // 测试 sheetNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setSheetNum(null))); + // 测试 purchaserAddress 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPurchaserAddress(null))); + // 测试 commodityUnit 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityUnit(null))); + // 测试 payee 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPayee(null))); + // 测试 commodityName 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCommodityName(null))); + // 测试 sellerName 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setSellerName(null))); + // 测试 invoiceCheck 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceCheck(null))); + // 测试 invoiceSeal 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceSeal(null))); + // 测试 invoiceQrcode 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceQrcode(null))); + // 测试 invoiceQrnum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceQrnum(null))); + // 测试 qrCheckCode 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setQrCheckCode(null))); + // 测试 invoiceState 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvoiceState(null))); + // 测试 printNum 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setPrintNum(null))); + // 测试 inoutMark 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInoutMark(null))); + // 测试 invalidMark 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setInvalidMark(null))); + // 测试 duplicateMark 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setDuplicateMark(null))); + // 测试 checkTrue 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCheckTrue(null))); + // 测试 encrypt 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setEncrypt(null))); + // 测试 createBy 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCreateBy(null))); + // 测试 createTime 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCreateTime(null))); + // 测试 recordId 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setRecordId(null))); + // 测试 companyId 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCompanyId(null))); + // 测试 company 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setCompany(null))); + // 测试 deptId 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setDeptId(null))); + // 测试 deptName 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setDeptName(null))); + // 测试 userId 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setUserId(null))); + // 测试 remark 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setRemark(null))); + // 测试 attr1 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAttr1(null))); + // 测试 attr2 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAttr2(null))); + // 测试 attr3 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAttr3(null))); + // 测试 attr4 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setAttr4(null))); + // 测试 archiveState 不匹配 + invoicesMapper.insert(cloneIgnoreId(dbInvoices, o -> o.setArchiveState(null))); + // 准备参数 + InvoicesExportReqVO reqVO = new InvoicesExportReqVO(); + reqVO.setVoucherId(null); + reqVO.setInvoiceCode(null); + reqVO.setInvoiceNum(null); + reqVO.setAmountinWords(null); + reqVO.setPrice(null); + reqVO.setTotalTax(null); + reqVO.setTaxRate(null); + reqVO.setTotalAmount(null); + reqVO.setCommodityTax(null); + reqVO.setCommodityAmount(null); + reqVO.setAmountinFiguers(null); + reqVO.setFoteDrawer(null); + reqVO.setSellerAddress(null); + reqVO.setCommodityNum(null); + reqVO.setSellerRegisterNum(null); + reqVO.setMachineCode(null); + reqVO.setRemarks(null); + reqVO.setSellerBank(null); + reqVO.setCheckCode(null); + reqVO.setInvoiceDate(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setPurchaserRegisterNum(null); + reqVO.setInvoiceTypeOrg(null); + reqVO.setPassword(null); + reqVO.setAgent(null); + reqVO.setPurchaserBank(null); + reqVO.setChecker(null); + reqVO.setCity(null); + reqVO.setPurchaserName(null); + reqVO.setCommodityType(null); + reqVO.setProvince(null); + reqVO.setInvoiceType(null); + reqVO.setSheetNum(null); + reqVO.setPurchaserAddress(null); + reqVO.setCommodityUnit(null); + reqVO.setPayee(null); + reqVO.setCommodityName(null); + reqVO.setSellerName(null); + reqVO.setInvoiceCheck(null); + reqVO.setInvoiceSeal(null); + reqVO.setInvoiceQrcode(null); + reqVO.setInvoiceQrnum(null); + reqVO.setQrCheckCode(null); + reqVO.setInvoiceState(null); + reqVO.setPrintNum(null); + reqVO.setInoutMark(null); + reqVO.setInvalidMark(null); + reqVO.setDuplicateMark(null); + reqVO.setCheckTrue(null); + reqVO.setEncrypt(null); + reqVO.setCreateBy(null); + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28)); + reqVO.setRecordId(null); + reqVO.setCompanyId(null); + reqVO.setCompany(null); + reqVO.setDeptId(null); + reqVO.setDeptName(null); + reqVO.setUserId(null); + reqVO.setRemark(null); + reqVO.setAttr1(null); + reqVO.setAttr2(null); + reqVO.setAttr3(null); + reqVO.setAttr4(null); + reqVO.setArchiveState(null); + + // 调用 + List list = invoicesService.getInvoicesList(reqVO); + // 断言 + assertEquals(1, list.size()); + assertPojoEquals(dbInvoices, list.get(0)); + } + +} diff --git a/yudao-module-bs/yudao-module-bs-biz/src/main/java/cn/iocoder/yudao/module/bs/utils/BaiduOcrConstant.java b/yudao-module-bs/yudao-module-bs-biz/src/main/java/cn/iocoder/yudao/module/bs/utils/BaiduOcrConstant.java index f0d6084b..97777bd4 100644 --- a/yudao-module-bs/yudao-module-bs-biz/src/main/java/cn/iocoder/yudao/module/bs/utils/BaiduOcrConstant.java +++ b/yudao-module-bs/yudao-module-bs-biz/src/main/java/cn/iocoder/yudao/module/bs/utils/BaiduOcrConstant.java @@ -14,13 +14,13 @@ public interface BaiduOcrConstant { * 需配置 * 百度智能云注册的应用程序API Key */ - String CLIENT_ID = "Aqp2823OP5H5lS7O94UvqXFb"; + String CLIENT_ID = "RTEtDalEDzlbwasifwNZbo32"; /** * 需配置 * 百度智能云注册的应用程序Secret Key */ - String CLIENT_SECRET = "qN9e4sSVCAcEWdwH3mUV8GMcWg3ujIvr"; + String CLIENT_SECRET = "eOLwdoCVHNsKzhKjVGTtzZBF4RVM0eu8"; /** * 身份证正面识别OCR接口地址 @@ -45,4 +45,14 @@ public interface BaiduOcrConstant { * 智能财务票据识别接口 */ String INVOICEURL = "https://aip.baidubce.com/rest/2.0/ocr/v1/multiple_invoice"; + + /** + * 增值税发票识别ofd、pdf + */ + String INVOICEURL_OFD = "https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice"; + + /** + * 增值税发票验真ofd、pdf + */ + String INVOICEURL_VERIFICATION = "https://aip.baidubce.com/rest/2.0/ocr/v1/vat_invoice_verification"; } \ No newline at end of file diff --git a/yudao-module-bs/yudao-module-bs-biz/src/main/java/cn/iocoder/yudao/module/bs/utils/BaiduOcrHandler.java b/yudao-module-bs/yudao-module-bs-biz/src/main/java/cn/iocoder/yudao/module/bs/utils/BaiduOcrHandler.java index 425f424b..bbd3d2d2 100644 --- a/yudao-module-bs/yudao-module-bs-biz/src/main/java/cn/iocoder/yudao/module/bs/utils/BaiduOcrHandler.java +++ b/yudao-module-bs/yudao-module-bs-biz/src/main/java/cn/iocoder/yudao/module/bs/utils/BaiduOcrHandler.java @@ -245,7 +245,7 @@ public class BaiduOcrHandler { * @return * @throws Exception */ - private static String getImageBase64Param(Object file) throws Exception { + public static String getImageBase64Param(Object file) throws Exception { File img; if (file instanceof File) { img = (File) file; @@ -333,4 +333,105 @@ public class BaiduOcrHandler { return null; } + /** + * 增值税发票识别 + * @param baseStr + * @param fileType + * @return + * @throws Exception + */ + public static JSONObject invoiceOCR(String baseStr, String fileType) throws Exception { + String accessToken = getAccessToken(); + if (StringUtils.isEmpty(accessToken)) { + throw new RuntimeException("获取token失败"); + } + String image = "image"; + if (fileType.equals("ofd")) { + image = "ofd_file"; + } + if (fileType.equals("pdf")) { + image = "pdf_file"; + } + String param = "verify_parameter=false&" + image + "=" +baseStr; + String jsonStr = HttpUtil.post(BaiduOcrConstant.INVOICEURL_OFD, accessToken, param); + JSONObject jsonObject = JSON.parseObject(jsonStr); + if (!jsonObject.containsKey("words_result")) { + log.error(baseStr+",ofd发票识别失败"+jsonObject.toString()); + throw exception("ofd发票识别失败"); + } + + return jsonObject; + } + + /** + * invoice_code 是 string - 发票代码。 + * 全电发票(专用发票)、全电发票(普通发票)此参数可为空,其他类型发票均不可为空 + * invoice_num 是 string - 发票号码 + * invoice_date 是 string - 开票日期。格式YYYYMMDD,例:20210101 + * invoice_type 是 string 增值税专用发票:special_vat_invoice + * 增值税电子专用发票:elec_special_vat_invoice + * 增值税普通发票:normal_invoice + * 增值税普通发票(电子):elec_normal_invoice + * 增值税普通发票(卷式):roll_normal_invoice + * 通行费增值税电子普通发票:toll_elec_normal_invoice + * 区块链电子发票(目前仅支持深圳地区):blockchain_invoice + * 全电发票(专用发票):elec_invoice_special + * 全电发票(普通发票):elec_invoice_normal + * 货运运输业增值税专用发票:special_freight_transport_invoice + * 机动车销售发票:motor_vehicle_invoice + * 二手车销售发票:used_vehicle_invoice 发票种类 + * check_code 是 string - 校验码。填写发票校验码后6位。 + * 增值税电子专票、普票、电子普票、卷票、区块链电子发票、通行费增值税电子普通发票此参数必填; + * 其他类型发票此参数可为空 + * total_amount 是 string - 发票金额。 + * 增值税专票、电子专票、区块链电子发票、机动车销售发票、货运专票填写不含税金额; + * 二手车销售发票填写车价合计; + * 全电发票(专用发票)、全电发票(普通发票)填写价税合计金额,其他类型发票可为空 + * + * 查验结果(VerifyResult) 查验结果信息(VerifyMessage) 描述 + * 9999 查验失败 查验失败,业务出现异常,请提交工单咨询 + * 0002 超过该张票当天查验次数 此发票今日查询次数已达上限(5次),请次日查询 + * 0005 请求不合法 发票信息有误,请核对后再查询 + * 0006 发票信息不一致 发票信息有误,请核对后再查询 + * 0009 发票不存在 所查发票不存在 + * 1004 已超过最大查验量 已超过最大查验量,请提交工单咨询 + * 1005 查询发票不规范 信息有误,请核对后再查询 + * 1006 查验异常 发票信息有误,请核对后再查询 + * 1008 字段不能为空 发票请求参数不能为空 + * 1009 参数长度不正确 参数长度不符合规范,确认参数,再次查验 + * 1014 日期当天的不能查验 日期当天的不能查验,请隔天再查 + * 1015 超过5年的不能查验 超过5年的不能查验 + * 1020 没有查验权限 没有查验权限,请提交工单咨询 + * 1021 网络超时 税局维护升级,暂时无法查验,请提交工单咨询 + * @param invoice_code + * @param invoice_num + * @param invoice_date + * @param invoice_type + * @param check_code + * @param total_amount + * @return + * @throws Exception + */ + public static JSONObject invoiceVerification(String invoice_code,String invoice_num, String invoice_date, String invoice_type, + String check_code,String total_amount) throws Exception { + String accessToken = getAccessToken(); + if (StringUtils.isEmpty(accessToken)) { + throw new RuntimeException("获取token失败"); + } + String param = "invoice_code="+invoice_code+"&"+ + "invoice_num="+invoice_num+"&"+ + "invoice_date="+invoice_date+"&"+ + "invoice_type="+invoice_type+"&"+ + "check_code="+check_code+"&"+ + "total_amount="+total_amount; + + String jsonStr = HttpUtil.post(BaiduOcrConstant.INVOICEURL_VERIFICATION, accessToken, param); + JSONObject jsonObject = JSON.parseObject(jsonStr); + if (!jsonObject.containsKey("words_result")) { + log.error(param+",发票验真识别失败"+jsonObject.toString()); + throw exception("发票验真识别失败"); + } + return jsonObject; + } + }