feat(einvoice): add electronic invoice module (T13.4)
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
package com.healthlink.his.web.einvoice.appservice;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceHeader;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface IEinvoiceAppService {
|
||||
EinvoiceHeader generate(EinvoiceHeader header);
|
||||
IPage<EinvoiceHeader> page(String invoiceStatus, String patientName, Integer pageNum, Integer pageSize);
|
||||
void voidInvoice(Long id, String reason);
|
||||
Map<String, Object> getReconciliation(Integer pageNum, Integer pageSize);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.healthlink.his.web.einvoice.appservice.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceHeader;
|
||||
import com.healthlink.his.einvoice.service.IEinvoiceHeaderService;
|
||||
import com.healthlink.his.einvoice.service.IEinvoiceReconciliationService;
|
||||
import com.healthlink.his.web.einvoice.appservice.IEinvoiceAppService;
|
||||
import com.core.common.utils.SecurityUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class EinvoiceAppServiceImpl implements IEinvoiceAppService {
|
||||
|
||||
@Autowired
|
||||
private IEinvoiceHeaderService headerService;
|
||||
|
||||
@Autowired
|
||||
private IEinvoiceReconciliationService reconciliationService;
|
||||
|
||||
@Override
|
||||
public EinvoiceHeader generate(EinvoiceHeader header) {
|
||||
header.setInvoiceNo("EINV" + System.currentTimeMillis());
|
||||
header.setInvoiceType("ELECTRONIC");
|
||||
header.setInvoiceStatus("ISSUED");
|
||||
header.setIssueTime(new Date());
|
||||
header.setIssuerName(SecurityUtils.getUsername());
|
||||
headerService.save(header);
|
||||
return header;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<EinvoiceHeader> page(String invoiceStatus, String patientName, Integer pageNum, Integer pageSize) {
|
||||
LambdaQueryWrapper<EinvoiceHeader> w = new LambdaQueryWrapper<>();
|
||||
if (StringUtils.hasText(invoiceStatus)) {
|
||||
w.eq(EinvoiceHeader::getInvoiceStatus, invoiceStatus);
|
||||
}
|
||||
if (StringUtils.hasText(patientName)) {
|
||||
w.like(EinvoiceHeader::getPatientName, patientName);
|
||||
}
|
||||
w.orderByDesc(EinvoiceHeader::getCreateTime);
|
||||
return headerService.page(new Page<>(pageNum, pageSize), w);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void voidInvoice(Long id, String reason) {
|
||||
EinvoiceHeader header = headerService.getById(id);
|
||||
if (header == null) {
|
||||
throw new RuntimeException("发票不存在");
|
||||
}
|
||||
header.setInvoiceStatus("VOID");
|
||||
header.setVoidTime(new Date());
|
||||
header.setVoidReason(reason);
|
||||
headerService.updateById(header);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getReconciliation(Integer pageNum, Integer pageSize) {
|
||||
LambdaQueryWrapper<EinvoiceHeader> w = new LambdaQueryWrapper<>();
|
||||
w.eq(EinvoiceHeader::getInvoiceStatus, "ISSUED");
|
||||
w.orderByDesc(EinvoiceHeader::getIssueTime);
|
||||
IPage<EinvoiceHeader> page = headerService.page(new Page<>(pageNum, pageSize), w);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("records", page.getRecords());
|
||||
result.put("total", page.getTotal());
|
||||
|
||||
LambdaQueryWrapper<EinvoiceHeader> totalW = new LambdaQueryWrapper<>();
|
||||
totalW.eq(EinvoiceHeader::getInvoiceStatus, "ISSUED");
|
||||
long totalCount = headerService.count(totalW);
|
||||
result.put("totalCount", totalCount);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.healthlink.his.web.einvoice.controller;
|
||||
|
||||
import com.core.common.core.domain.AjaxResult;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceHeader;
|
||||
import com.healthlink.his.web.einvoice.appservice.IEinvoiceAppService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Tag(name = "电子票据管理")
|
||||
@RestController
|
||||
@RequestMapping("/invoice")
|
||||
public class EinvoiceController {
|
||||
|
||||
@Autowired
|
||||
private IEinvoiceAppService einvoiceAppService;
|
||||
|
||||
@Operation(summary = "生成电子票据")
|
||||
@PreAuthorize("@ss.hasPermi('basicmanage:invoice:edit')")
|
||||
@PostMapping("/generate")
|
||||
public AjaxResult generate(@RequestBody EinvoiceHeader header) {
|
||||
return AjaxResult.success(einvoiceAppService.generate(header));
|
||||
}
|
||||
|
||||
@Operation(summary = "电子票据分页")
|
||||
@PreAuthorize("@ss.hasPermi('basicmanage:invoice:list')")
|
||||
@GetMapping("/page")
|
||||
public AjaxResult page(@RequestParam(required = false) String invoiceStatus,
|
||||
@RequestParam(required = false) String patientName,
|
||||
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize) {
|
||||
return AjaxResult.success(einvoiceAppService.page(invoiceStatus, patientName, pageNum, pageSize));
|
||||
}
|
||||
|
||||
@Operation(summary = "作废电子票据")
|
||||
@PreAuthorize("@ss.hasPermi('basicmanage:invoice:edit')")
|
||||
@PostMapping("/void")
|
||||
public AjaxResult voidInvoice(@RequestParam Long id, @RequestParam(required = false) String reason) {
|
||||
einvoiceAppService.voidInvoice(id, reason);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
@Operation(summary = "票据对账")
|
||||
@PreAuthorize("@ss.hasPermi('basicmanage:invoice:list')")
|
||||
@GetMapping("/reconciliation")
|
||||
public AjaxResult reconciliation(@RequestParam(defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize) {
|
||||
return AjaxResult.success(einvoiceAppService.getReconciliation(pageNum, pageSize));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
CREATE TABLE IF NOT EXISTS invoice_header (
|
||||
id BIGINT PRIMARY KEY,
|
||||
invoice_no VARCHAR(64) NOT NULL,
|
||||
invoice_type VARCHAR(20) NOT NULL DEFAULT 'ELECTRONIC',
|
||||
encounter_id BIGINT,
|
||||
patient_id BIGINT,
|
||||
patient_name VARCHAR(64),
|
||||
total_amount NUMERIC(12,2) NOT NULL DEFAULT 0,
|
||||
discount_amount NUMERIC(12,2) DEFAULT 0,
|
||||
payable_amount NUMERIC(12,2) NOT NULL DEFAULT 0,
|
||||
paid_amount NUMERIC(12,2) DEFAULT 0,
|
||||
invoice_status VARCHAR(20) NOT NULL DEFAULT 'ISSUED',
|
||||
issue_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
void_time TIMESTAMP,
|
||||
void_reason VARCHAR(256),
|
||||
issuer_id BIGINT,
|
||||
issuer_name VARCHAR(64),
|
||||
create_by VARCHAR(64),
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
update_by VARCHAR(64),
|
||||
update_time TIMESTAMP,
|
||||
tenant_id INT DEFAULT 1,
|
||||
delete_flag VARCHAR(1) DEFAULT '0'
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS invoice_detail (
|
||||
id BIGINT PRIMARY KEY,
|
||||
header_id BIGINT NOT NULL,
|
||||
item_code VARCHAR(64),
|
||||
item_name VARCHAR(128) NOT NULL,
|
||||
item_type VARCHAR(20),
|
||||
quantity NUMERIC(10,2) DEFAULT 1,
|
||||
unit_price NUMERIC(12,2) DEFAULT 0,
|
||||
amount NUMERIC(12,2) NOT NULL DEFAULT 0,
|
||||
create_by VARCHAR(64),
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
update_by VARCHAR(64),
|
||||
update_time TIMESTAMP,
|
||||
tenant_id INT DEFAULT 1,
|
||||
delete_flag VARCHAR(1) DEFAULT '0'
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS invoice_segment (
|
||||
id BIGINT PRIMARY KEY,
|
||||
segment_name VARCHAR(128) NOT NULL,
|
||||
start_no VARCHAR(64) NOT NULL,
|
||||
end_no VARCHAR(64) NOT NULL,
|
||||
current_no VARCHAR(64),
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
|
||||
invoice_type VARCHAR(20) DEFAULT 'ELECTRONIC',
|
||||
create_by VARCHAR(64),
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
update_by VARCHAR(64),
|
||||
update_time TIMESTAMP,
|
||||
tenant_id INT DEFAULT 1,
|
||||
delete_flag VARCHAR(1) DEFAULT '0'
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS invoice_reconciliation (
|
||||
id BIGINT PRIMARY KEY,
|
||||
recon_date DATE NOT NULL,
|
||||
total_invoices INT DEFAULT 0,
|
||||
total_amount NUMERIC(14,2) DEFAULT 0,
|
||||
reconciled_count INT DEFAULT 0,
|
||||
reconciled_amount NUMERIC(14,2) DEFAULT 0,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
|
||||
reconciler_id BIGINT,
|
||||
reconciler_name VARCHAR(64),
|
||||
reconcile_time TIMESTAMP,
|
||||
create_by VARCHAR(64),
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
update_by VARCHAR(64),
|
||||
update_time TIMESTAMP,
|
||||
tenant_id INT DEFAULT 1,
|
||||
delete_flag VARCHAR(1) DEFAULT '0'
|
||||
);
|
||||
|
||||
CREATE INDEX idx_inv_header_no ON invoice_header(invoice_no);
|
||||
CREATE INDEX idx_inv_header_status ON invoice_header(invoice_status);
|
||||
CREATE INDEX idx_inv_header_patient ON invoice_header(patient_id);
|
||||
CREATE INDEX idx_inv_detail_header ON invoice_detail(header_id);
|
||||
CREATE INDEX idx_inv_recon_date ON invoice_reconciliation(recon_date);
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.healthlink.his.einvoice.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.core.common.core.domain.HisBaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@TableName("invoice_detail")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class EinvoiceDetail extends HisBaseEntity {
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long headerId;
|
||||
private String itemCode;
|
||||
private String itemName;
|
||||
private String itemType;
|
||||
private BigDecimal quantity;
|
||||
private BigDecimal unitPrice;
|
||||
private BigDecimal amount;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.healthlink.his.einvoice.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.core.common.core.domain.HisBaseEntity;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@TableName("invoice_header")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class EinvoiceHeader extends HisBaseEntity {
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
private String invoiceNo;
|
||||
private String invoiceType;
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long encounterId;
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long patientId;
|
||||
private String patientName;
|
||||
private BigDecimal totalAmount;
|
||||
private BigDecimal discountAmount;
|
||||
private BigDecimal payableAmount;
|
||||
private BigDecimal paidAmount;
|
||||
private String invoiceStatus;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date issueTime;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date voidTime;
|
||||
private String voidReason;
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long issuerId;
|
||||
private String issuerName;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.healthlink.his.einvoice.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.core.common.core.domain.HisBaseEntity;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
@TableName("invoice_reconciliation")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class EinvoiceReconciliation extends HisBaseEntity {
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date reconDate;
|
||||
private Integer totalInvoices;
|
||||
private BigDecimal totalAmount;
|
||||
private Integer reconciledCount;
|
||||
private BigDecimal reconciledAmount;
|
||||
private String status;
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long reconcilerId;
|
||||
private String reconcilerName;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date reconcileTime;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.healthlink.his.einvoice.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.core.common.core.domain.HisBaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
|
||||
@Data
|
||||
@TableName("invoice_segment")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class EinvoiceSegment extends HisBaseEntity {
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
private String segmentName;
|
||||
private String startNo;
|
||||
private String endNo;
|
||||
private String currentNo;
|
||||
private String status;
|
||||
private String invoiceType;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.healthlink.his.einvoice.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceDetail;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface EinvoiceDetailMapper extends BaseMapper<EinvoiceDetail> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.healthlink.his.einvoice.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceHeader;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface EinvoiceHeaderMapper extends BaseMapper<EinvoiceHeader> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.healthlink.his.einvoice.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceReconciliation;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface EinvoiceReconciliationMapper extends BaseMapper<EinvoiceReconciliation> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.healthlink.his.einvoice.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceSegment;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@Mapper
|
||||
public interface EinvoiceSegmentMapper extends BaseMapper<EinvoiceSegment> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.healthlink.his.einvoice.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceDetail;
|
||||
|
||||
public interface IEinvoiceDetailService extends IService<EinvoiceDetail> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.healthlink.his.einvoice.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceHeader;
|
||||
|
||||
public interface IEinvoiceHeaderService extends IService<EinvoiceHeader> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.healthlink.his.einvoice.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceReconciliation;
|
||||
|
||||
public interface IEinvoiceReconciliationService extends IService<EinvoiceReconciliation> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.healthlink.his.einvoice.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceSegment;
|
||||
|
||||
public interface IEinvoiceSegmentService extends IService<EinvoiceSegment> {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.healthlink.his.einvoice.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceDetail;
|
||||
import com.healthlink.his.einvoice.mapper.EinvoiceDetailMapper;
|
||||
import com.healthlink.his.einvoice.service.IEinvoiceDetailService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class EinvoiceDetailServiceImpl extends ServiceImpl<EinvoiceDetailMapper, EinvoiceDetail> implements IEinvoiceDetailService {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.healthlink.his.einvoice.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceHeader;
|
||||
import com.healthlink.his.einvoice.mapper.EinvoiceHeaderMapper;
|
||||
import com.healthlink.his.einvoice.service.IEinvoiceHeaderService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class EinvoiceHeaderServiceImpl extends ServiceImpl<EinvoiceHeaderMapper, EinvoiceHeader> implements IEinvoiceHeaderService {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.healthlink.his.einvoice.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceReconciliation;
|
||||
import com.healthlink.his.einvoice.mapper.EinvoiceReconciliationMapper;
|
||||
import com.healthlink.his.einvoice.service.IEinvoiceReconciliationService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class EinvoiceReconciliationServiceImpl extends ServiceImpl<EinvoiceReconciliationMapper, EinvoiceReconciliation> implements IEinvoiceReconciliationService {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.healthlink.his.einvoice.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.healthlink.his.einvoice.domain.EinvoiceSegment;
|
||||
import com.healthlink.his.einvoice.mapper.EinvoiceSegmentMapper;
|
||||
import com.healthlink.his.einvoice.service.IEinvoiceSegmentService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class EinvoiceSegmentServiceImpl extends ServiceImpl<EinvoiceSegmentMapper, EinvoiceSegment> implements IEinvoiceSegmentService {
|
||||
}
|
||||
204
healthlink-his-ui/src/views/einvoice/InvoiceManagement.vue
Normal file
204
healthlink-his-ui/src/views/einvoice/InvoiceManagement.vue
Normal file
@@ -0,0 +1,204 @@
|
||||
<template>
|
||||
<div style="padding: 16px">
|
||||
<div style="margin-bottom: 16px; display: flex; justify-content: space-between; align-items: center">
|
||||
<span style="font-size: 18px; font-weight: bold">电子票据管理</span>
|
||||
<el-button type="primary" @click="handleGenerate">开具票据</el-button>
|
||||
</div>
|
||||
|
||||
<el-card shadow="never" style="margin-bottom: 16px">
|
||||
<div style="display: flex; gap: 8px; flex-wrap: wrap; align-items: center">
|
||||
<el-input v-model="query.patientName" placeholder="患者姓名" clearable style="width: 160px" />
|
||||
<el-select v-model="query.invoiceStatus" placeholder="状态" clearable style="width: 120px">
|
||||
<el-option label="已开具" value="ISSUED" />
|
||||
<el-option label="已作废" value="VOID" />
|
||||
</el-select>
|
||||
<el-button type="primary" @click="loadPage">查询</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
<el-button @click="showReconciliation">对账</el-button>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never">
|
||||
<el-table :data="tableData" v-loading="loading" border stripe>
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="invoiceNo" label="票据号" width="200" />
|
||||
<el-table-column prop="patientName" label="患者姓名" width="120" />
|
||||
<el-table-column prop="totalAmount" label="总金额" width="120" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.totalAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="discountAmount" label="优惠金额" width="120" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.discountAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="payableAmount" label="应付金额" width="120" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.payableAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="invoiceStatus" label="状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.invoiceStatus === 'ISSUED'" type="success">已开具</el-tag>
|
||||
<el-tag v-else-if="row.invoiceStatus === 'VOID'" type="danger">已作废</el-tag>
|
||||
<el-tag v-else>{{ row.invoiceStatus }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="issueTime" label="开具时间" width="170" />
|
||||
<el-table-column label="操作" width="100" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.invoiceStatus === 'ISSUED'" type="danger" size="small" @click="handleVoid(row)">作废</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
v-model:current-page="query.pageNum"
|
||||
v-model:page-size="query.pageSize"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next"
|
||||
style="margin-top: 16px; justify-content: flex-end"
|
||||
@size-change="loadPage"
|
||||
@current-change="loadPage"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="generateVisible" title="开具电子票据" width="500px">
|
||||
<el-form :model="generateForm" label-width="90px">
|
||||
<el-form-item label="就诊ID">
|
||||
<el-input v-model="generateForm.encounterId" placeholder="就诊ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="患者ID">
|
||||
<el-input v-model="generateForm.patientId" placeholder="患者ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="患者姓名">
|
||||
<el-input v-model="generateForm.patientName" placeholder="患者姓名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="总金额">
|
||||
<el-input v-model="generateForm.totalAmount" placeholder="总金额" />
|
||||
</el-form-item>
|
||||
<el-form-item label="优惠金额">
|
||||
<el-input v-model="generateForm.discountAmount" placeholder="优惠金额" />
|
||||
</el-form-item>
|
||||
<el-form-item label="应付金额">
|
||||
<el-input v-model="generateForm.payableAmount" placeholder="应付金额" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="generateVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="submitGenerate">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="voidVisible" title="作废票据" width="400px">
|
||||
<el-form label-width="80px">
|
||||
<el-form-item label="作废原因">
|
||||
<el-input v-model="voidReason" type="textarea" :rows="3" placeholder="请输入作废原因" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="voidVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmVoid">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="reconVisible" title="票据对账" width="700px">
|
||||
<el-table :data="reconData" border stripe v-loading="reconLoading">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="invoiceNo" label="票据号" width="200" />
|
||||
<el-table-column prop="patientName" label="患者姓名" width="120" />
|
||||
<el-table-column prop="payableAmount" label="应付金额" width="120" align="right">
|
||||
<template #default="{ row }">{{ formatMoney(row.payableAmount) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="invoiceStatus" label="状态" width="100">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.invoiceStatus === 'ISSUED'" type="success">已开具</el-tag>
|
||||
<el-tag v-else>{{ row.invoiceStatus }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="issueTime" label="开具时间" width="170" />
|
||||
</el-table>
|
||||
<div style="margin-top: 12px; color: #666">
|
||||
共 {{ reconTotal }} 条已开具票据
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { generateInvoice, getInvoicePage, voidInvoice, getReconciliation } from './api'
|
||||
|
||||
const loading = ref(false)
|
||||
const tableData = ref([])
|
||||
const total = ref(0)
|
||||
const query = ref({ invoiceStatus: '', patientName: '', pageNum: 1, pageSize: 10 })
|
||||
|
||||
const generateVisible = ref(false)
|
||||
const generateForm = ref({ encounterId: '', patientId: '', patientName: '', totalAmount: 0, discountAmount: 0, payableAmount: 0 })
|
||||
|
||||
const voidVisible = ref(false)
|
||||
const voidReason = ref('')
|
||||
const voidRow = ref(null)
|
||||
|
||||
const reconVisible = ref(false)
|
||||
const reconLoading = ref(false)
|
||||
const reconData = ref([])
|
||||
const reconTotal = ref(0)
|
||||
|
||||
function formatMoney(val) {
|
||||
if (!val) return '0.00'
|
||||
return Number(val).toFixed(2)
|
||||
}
|
||||
|
||||
async function loadPage() {
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await getInvoicePage(query.value)
|
||||
tableData.value = res.data?.records || []
|
||||
total.value = res.data?.total || 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
query.value = { invoiceStatus: '', patientName: '', pageNum: 1, pageSize: 10 }
|
||||
loadPage()
|
||||
}
|
||||
|
||||
function handleGenerate() {
|
||||
generateForm.value = { encounterId: '', patientId: '', patientName: '', totalAmount: 0, discountAmount: 0, payableAmount: 0 }
|
||||
generateVisible.value = true
|
||||
}
|
||||
|
||||
async function submitGenerate() {
|
||||
await generateInvoice(generateForm.value)
|
||||
ElMessage.success('开具成功')
|
||||
generateVisible.value = false
|
||||
loadPage()
|
||||
}
|
||||
|
||||
function handleVoid(row) {
|
||||
voidRow.value = row
|
||||
voidReason.value = ''
|
||||
voidVisible.value = true
|
||||
}
|
||||
|
||||
async function confirmVoid() {
|
||||
await voidInvoice({ id: voidRow.value.id, reason: voidReason.value })
|
||||
ElMessage.success('作废成功')
|
||||
voidVisible.value = false
|
||||
loadPage()
|
||||
}
|
||||
|
||||
async function showReconciliation() {
|
||||
reconVisible.value = true
|
||||
reconLoading.value = true
|
||||
try {
|
||||
const res = await getReconciliation({ pageNum: 1, pageSize: 50 })
|
||||
reconData.value = res.data?.records || []
|
||||
reconTotal.value = res.data?.totalCount || 0
|
||||
} finally {
|
||||
reconLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => loadPage())
|
||||
</script>
|
||||
17
healthlink-his-ui/src/views/einvoice/api.js
Normal file
17
healthlink-his-ui/src/views/einvoice/api.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function generateInvoice(data) {
|
||||
return request({ url: '/invoice/generate', method: 'post', data })
|
||||
}
|
||||
|
||||
export function getInvoicePage(params) {
|
||||
return request({ url: '/invoice/page', method: 'get', params })
|
||||
}
|
||||
|
||||
export function voidInvoice(params) {
|
||||
return request({ url: '/invoice/void', method: 'post', params })
|
||||
}
|
||||
|
||||
export function getReconciliation(params) {
|
||||
return request({ url: '/invoice/reconciliation', method: 'get', params })
|
||||
}
|
||||
Reference in New Issue
Block a user