invoice_validation_example.md
13.4 KB
发票验证功能使用示例
场景说明
本示例展示了发票验证功能的工作方式,包括成功场景和失败场景。
成功场景
场景1:所有经销商信息一致
输入数据:
- 订单编号:
ORDER001 - 订单中的经销商编码:
DEALER001 - 出库单编号:
DELIVERY001 - 出库单中的经销商编码:
DEALER001 - 发票中的经销商编码:
DEALER001
验证结果: ✅ 通过验证,继续执行发票创建/修改流程
代码示例:
// 订单信息
OrderMain order = new OrderMain();
order.setOrderNo("ORDER001");
order.setDealerCode("DEALER001");
// 出库单信息
DeliveryMain delivery = new DeliveryMain();
delivery.setDeliveryNo("DELIVERY001");
delivery.setDealerCode("DEALER001");
// 发票请求
InvoiceAddReq addReq = new InvoiceAddReq();
addReq.setOrderNo("ORDER001");
addReq.setDeliveryNo("DELIVERY001");
addReq.setDealerCode("DEALER001");
// 验证通过,继续执行
invoiceMainService.addInvoice(addReq);
场景2:不提供出库单号
输入数据:
- 订单编号:
ORDER001 - 订单中的经销商编码:
DEALER001 - 发票中的经销商编码:
DEALER001 - 出库单编号:
null(不提供)
验证结果: ✅ 通过验证,只验证订单经销商一致性
代码示例:
// 发票请求(不提供出库单号)
InvoiceAddReq addReq = new InvoiceAddReq();
addReq.setOrderNo("ORDER001");
addReq.setDeliveryNo(null); // 不提供出库单号
addReq.setDealerCode("DEALER001");
// 验证通过,只验证订单经销商一致性
invoiceMainService.addInvoice(addReq);
失败场景
场景3:发票与订单经销商不一致
输入数据:
- 订单编号:
ORDER001 - 订单中的经销商编码:
DEALER001 - 发票中的经销商编码:
DEALER002
验证结果: ❌ 验证失败,抛出 InvoiceValidationException
异常信息:
发票中的经销商编码[DEALER002]与关联订单[ORDER001]中的经销商编码[DEALER001]不一致
代码示例:
// 发票请求(经销商编码不匹配)
InvoiceAddReq addReq = new InvoiceAddReq();
addReq.setOrderNo("ORDER001");
addReq.setDealerCode("DEALER002"); // 不匹配的经销商编码
// 验证失败,抛出异常
try {
invoiceMainService.addInvoice(addReq);
} catch (InvoiceValidationException e) {
System.out.println("验证失败:" + e.getMessage());
// 输出:验证失败:发票中的经销商编码[DEALER002]与关联订单[ORDER001]中的经销商编码[DEALER001]不一致
}
场景4:发票与出库单经销商不一致
输入数据:
- 订单编号:
ORDER001 - 订单中的经销商编码:
DEALER001 - 出库单编号:
DELIVERY001 - 出库单中的经销商编码:
DEALER001 - 发票中的经销商编码:
DEALER002
验证结果: ❌ 验证失败,抛出 InvoiceValidationException
异常信息:
发票中的经销商编码[DEALER002]与关联出库单[DELIVERY001]中的经销商编码[DEALER001]不一致
代码示例:
// 发票请求(出库单经销商编码不匹配)
InvoiceAddReq addReq = new InvoiceAddReq();
addReq.setOrderNo("ORDER001");
addReq.setDeliveryNo("DELIVERY001");
addReq.setDealerCode("DEALER002"); // 不匹配的经销商编码
// 验证失败,抛出异常
try {
invoiceMainService.addInvoice(addReq);
} catch (InvoiceValidationException e) {
System.out.println("验证失败:" + e.getMessage());
// 输出:验证失败:发票中的经销商编码[DEALER002]与关联出库单[DELIVERY001]中的经销商编码[DEALER001]不一致
}
场景5:关联订单不存在
输入数据:
- 订单编号:
ORDER999(不存在的订单) - 发票中的经销商编码:
DEALER001
验证结果: ❌ 验证失败,抛出 IllegalArgumentException
异常信息:
关联的订单不存在
代码示例:
// 发票请求(关联不存在的订单)
InvoiceAddReq addReq = new InvoiceAddReq();
addReq.setOrderNo("ORDER999"); // 不存在的订单
addReq.setDealerCode("DEALER001");
// 验证失败,抛出异常
try {
invoiceMainService.addInvoice(addReq);
} catch (IllegalArgumentException e) {
System.out.println("验证失败:" + e.getMessage());
// 输出:验证失败:关联的订单不存在
}
场景6:关联出库单不存在
输入数据:
- 订单编号:
ORDER001 - 订单中的经销商编码:
DEALER001 - 出库单编号:
DELIVERY999(不存在的出库单) - 发票中的经销商编码:
DEALER001
验证结果: ❌ 验证失败,抛出 IllegalArgumentException
异常信息:
关联的出库单不存在
代码示例:
// 发票请求(关联不存在的出库单)
InvoiceAddReq addReq = new InvoiceAddReq();
addReq.setOrderNo("ORDER001");
addReq.setDeliveryNo("DELIVERY999"); // 不存在的出库单
addReq.setDealerCode("DEALER001");
// 验证失败,抛出异常
try {
invoiceMainService.addInvoice(addReq);
} catch (IllegalArgumentException e) {
System.out.println("验证失败:" + e.getMessage());
// 输出:验证失败:关联的出库单不存在
}
API调用示例
新增发票
请求:
POST /api/invoice/add
Content-Type: application/json
{
"invoiceNo": "INVOICE001",
"orderNo": "ORDER001",
"deliveryNo": "DELIVERY001",
"dealerCode": "DEALER002", // 与订单和出库单中的经销商不一致
"dealerName": "测试经销商",
"totalAmount": 1000.00,
"invoiceDate": "2024-01-15",
"invoiceItems": [
{
"productCode": "PRODUCT001",
"invoiceQty": 10,
"amountNoTax": 1000.00
}
]
}
响应(失败):
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"code": 400,
"message": "发票中的经销商编码[DEALER002]与关联订单[ORDER001]中的经销商编码[DEALER001]不一致",
"timestamp": "2024-01-15T10:00:00"
}
修改发票
请求:
PUT /api/invoice/update
Content-Type: application/json
{
"invoiceId": 1,
"invoiceNo": "INVOICE001",
"orderNo": "ORDER001",
"deliveryNo": "DELIVERY001",
"dealerCode": "DEALER001", // 与订单和出库单中的经销商一致
"dealerName": "测试经销商",
"totalAmount": 1000.00,
"invoiceDate": "2024-01-15",
"invoiceItems": [
{
"productCode": "PRODUCT001",
"invoiceQty": 10,
"amountNoTax": 1000.00
}
]
}
响应(成功):
HTTP/1.1 200 OK
Content-Type: application/json
{
"code": 200,
"message": "发票修改成功",
"data": true
}
前端处理示例
JavaScript错误处理
// 新增发票
async function addInvoice(invoiceData) {
try {
const response = await fetch('/api/invoice/add', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(invoiceData)
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message);
}
const result = await response.json();
console.log('发票创建成功', result);
} catch (error) {
if (error.message.includes('发票中的经销商编码') && error.message.includes('与关联订单') && error.message.includes('不一致')) {
// 处理订单经销商不匹配错误
alert('错误:发票中的经销商与关联订单中的经销商不一致,请检查经销商信息');
} else if (error.message.includes('发票中的经销商编码') && error.message.includes('与关联出库单') && error.message.includes('不一致')) {
// 处理出库单经销商不匹配错误
alert('错误:发票中的经销商与关联出库单中的经销商不一致,请检查经销商信息');
} else if (error.message.includes('关联的订单不存在')) {
// 处理订单不存在错误
alert('错误:关联的订单不存在,请检查订单编号');
} else if (error.message.includes('关联的出库单不存在')) {
// 处理出库单不存在错误
alert('错误:关联的出库单不存在,请检查出库单编号');
} else {
// 处理其他错误
alert('发票创建失败:' + error.message);
}
}
}
最佳实践
1. 数据录入时验证
在用户录入发票信息时,可以实时验证经销商信息:
// 当订单编号改变时,自动填充经销商信息
async function onOrderNoChange(orderNo) {
if (orderNo) {
try {
const order = await getOrderByNo(orderNo);
if (order) {
// 自动填充经销商信息
document.getElementById('dealerCode').value = order.dealerCode;
document.getElementById('dealerName').value = order.dealerName;
}
} catch (error) {
console.error('获取订单信息失败', error);
}
}
}
// 当出库单编号改变时,验证经销商信息
async function onDeliveryNoChange(deliveryNo) {
if (deliveryNo) {
try {
const delivery = await getDeliveryByNo(deliveryNo);
if (delivery) {
const currentDealerCode = document.getElementById('dealerCode').value;
if (currentDealerCode && currentDealerCode !== delivery.dealerCode) {
alert('警告:出库单中的经销商与当前选择的经销商不一致');
}
}
} catch (error) {
console.error('获取出库单信息失败', error);
}
}
}
2. 表单验证
在提交前进行客户端验证:
function validateInvoiceForm() {
const orderNo = document.getElementById('orderNo').value;
const deliveryNo = document.getElementById('deliveryNo').value;
const dealerCode = document.getElementById('dealerCode').value;
if (orderNo && dealerCode) {
// 可以调用API验证经销商一致性
return validateDealerConsistency(orderNo, deliveryNo, dealerCode);
}
return true;
}
3. 错误提示优化
提供更友好的错误提示:
function handleInvoiceValidationError(error) {
const errorMessage = error.message;
if (errorMessage.includes('发票中的经销商编码') && errorMessage.includes('与关联订单') && errorMessage.includes('不一致')) {
return {
type: 'warning',
title: '订单经销商信息不匹配',
message: '发票中的经销商与关联订单中的经销商不一致,请确认经销商信息是否正确',
action: '请检查并修正经销商编码,或选择正确的订单'
};
} else if (errorMessage.includes('发票中的经销商编码') && errorMessage.includes('与关联出库单') && errorMessage.includes('不一致')) {
return {
type: 'warning',
title: '出库单经销商信息不匹配',
message: '发票中的经销商与关联出库单中的经销商不一致,请确认经销商信息是否正确',
action: '请检查并修正经销商编码,或选择正确的出库单'
};
} else if (errorMessage.includes('关联的订单不存在')) {
return {
type: 'error',
title: '订单不存在',
message: '关联的订单不存在,请检查订单编号是否正确',
action: '请检查订单编号或选择其他订单'
};
} else if (errorMessage.includes('关联的出库单不存在')) {
return {
type: 'error',
title: '出库单不存在',
message: '关联的出库单不存在,请检查出库单编号是否正确',
action: '请检查出库单编号或选择其他出库单'
};
}
return {
type: 'error',
title: '验证失败',
message: errorMessage
};
}
4. 数据联动
实现订单、出库单、发票之间的数据联动:
// 根据订单自动填充相关信息
async function loadOrderInfo(orderNo) {
try {
const order = await getOrderByNo(orderNo);
if (order) {
// 填充经销商信息
document.getElementById('dealerCode').value = order.dealerCode;
document.getElementById('dealerName').value = order.dealerName;
// 加载相关的出库单列表
const deliveries = await getDeliveriesByOrderNo(orderNo);
updateDeliveryOptions(deliveries);
}
} catch (error) {
console.error('加载订单信息失败', error);
}
}
// 根据出库单自动填充相关信息
async function loadDeliveryInfo(deliveryNo) {
try {
const delivery = await getDeliveryByNo(deliveryNo);
if (delivery) {
// 验证经销商信息是否一致
const currentDealerCode = document.getElementById('dealerCode').value;
if (currentDealerCode && currentDealerCode !== delivery.dealerCode) {
showWarning('出库单中的经销商与当前选择的经销商不一致');
}
}
} catch (error) {
console.error('加载出库单信息失败', error);
}
}