月薪2万,在大厂干了10年被裁了,拿了30万赔偿金,五年后HR联系我,问我愿不愿意回去,但要归还30万,我该回去吗?
刚看到个贴子,说有个网友在大厂月薪2万干了10年被裁,拿了30万赔偿。五年后公司又来找,说可以回去,但前提是把当年的30万还回去,他就纠结要不要答应。
网友回复我看了看,有的说“钱不能退,人也别回”,有的觉得“只要给得起现在的价,退点也行”。
我觉得这事吧,先别被情绪带跑。第一,那30万本质是公司当时为裁员付的成本,法律和感情上都没理由原封退回;现在让你退,相当于默认当年那刀可以白砍。第二,就算不谈原则,也得算账:同岗位现在的薪资、发展、稳定性和你手里的机会比一比。
真香就当新工作谈,条件不到位,别被“回锅情怀”绑架。
面试题:发票中的产品金额
想象你在给公司做个开票系统,财务小姐姐丢给你一句话: “我这边有总金额、税率、每个商品的数量单价,你给我把每个商品行的金额算对,保留两位小数,还得保证所有行加起来刚好等于发票总额,不能差一分钱。”
听着挺简单对吧,单价乘数量嘛。真上手你就会发现,坑全在“保留两位小数”和“最后要对得上”这俩词上。
我们简化一下需求,发票上每一行有这些东西:
商品名 数量 单价(不含税) 折扣(可选,比如 9 折) 税率(比如 13%)
要做的事有两步:
算出每一行「含税金额」,保留两位小数; 所有行金额加起来,要和发票总金额一模一样。因为四舍五入可能会有几分钱的误差,这就得搞一个“分摊算法”。
所以这是个“计算 + 分摊”的小算发题,用 Java 写比较典型: 避坑要点两个字:BigDecimal。
先不管分摊问题,单行金额其实就三步:
原始金额 = 单价 × 数量 折扣后金额 = 原始金额 × (1 - 折扣率) 含税金额 = 折扣后金额 × (1 + 税率),最后保留两位小数
直接上段 Java 小例子,你感受下写法就行:
import java.math.BigDecimal;
import java.math.RoundingMode;
publicclassInvoiceItem{
private String name;
privateint quantity;
private BigDecimal unitPrice; // 不含税单价
private BigDecimal discount; // 0.1 表示打 9 折
private BigDecimal taxRate; // 0.13 表示 13%
publicInvoiceItem(String name, int quantity,
BigDecimal unitPrice,
BigDecimal discount,
BigDecimal taxRate){
this.name = name;
this.quantity = quantity;
this.unitPrice = unitPrice;
this.discount = discount;
this.taxRate = taxRate;
}
// 计算这一行的含税金额
public BigDecimal calcAmountWithTax(){
BigDecimal qty = BigDecimal.valueOf(quantity);
// 原始金额 = 单价 * 数量
BigDecimal raw = unitPrice.multiply(qty);
// 折扣后金额 = 原始金额 * (1 - discount)
BigDecimal discountFactor = BigDecimal.ONE.subtract(discount);
BigDecimal afterDiscount = raw.multiply(discountFactor);
// 含税金额 = 折扣后金额 * (1 + taxRate)
BigDecimal taxFactor = BigDecimal.ONE.add(taxRate);
BigDecimal withTax = afterDiscount.multiply(taxFactor);
// 保留两位小数,四舍五入
return withTax.setScale(2, RoundingMode.HALF_UP);
}
public String getName(){
return name;
}
}
这里有两个小细节你一定要注意一下:
千万别用 double,用BigDecimal,钱都是这样算的;setScale(2, RoundingMode.HALF_UP),别偷懒用默认构造,不然有时候会直接抛异常。
问题来了,就算每一行你都算对了,两位小数也都对,但所有行加起来,和发票总金额,可能会差个 0.01 或 0.02。
举个极端例子: 有三行商品,理论精确金额是:
33.335 33.335 33.335
四舍五入后每行都是 33.34,那三行加起来就 100.02 但财务要求发票总额就是 100.01 或 100.00,这就不对了。
怎么办?思路很简单:先按正常公式算出每一行,再看差额是多少,最后把差额摊到某一行(或者几行)里去。
最粗暴也最好实现的一种就是: 差额全丢给金额最大的那一行。
我们写个小工具类,把“算行金额”和“分摊误差”都串起来:
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
publicclassInvoiceCalculator{
publicstaticclassLineAmount{
public InvoiceItem item;
public BigDecimal amount; // 已经保留两位小数
publicLineAmount(InvoiceItem item, BigDecimal amount){
this.item = item;
this.amount = amount;
}
}
/**
* 计算每行金额,并按照发票总额做差额分摊
*/
publicstatic List<LineAmount> calcWithAdjust(List<InvoiceItem> items,
BigDecimal invoiceTotal){
List<LineAmount> result = new ArrayList<>();
// 1. 先算出每一行的金额
BigDecimal sum = BigDecimal.ZERO;
int maxIndex = 0;
BigDecimal maxAmount = BigDecimal.ZERO;
for (int i = 0; i < items.size(); i++) {
InvoiceItem item = items.get(i);
BigDecimal amount = item.calcAmountWithTax();
result.add(new LineAmount(item, amount));
sum = sum.add(amount);
// 记录最大金额的那一行
if (amount.compareTo(maxAmount) > 0) {
maxAmount = amount;
maxIndex = i;
}
}
// 2. 计算差额 = 发票总额 - 行小计之和
BigDecimal diff = invoiceTotal.subtract(sum);
// 如果差额非 0,就把差额加到最大金额的那一行
if (diff.compareTo(BigDecimal.ZERO) != 0) {
LineAmount line = result.get(maxIndex);
line.amount = line.amount.add(diff)
.setScale(2, RoundingMode.HALF_UP);
}
return result;
}
}
再来个简单 main,把流程跑通:
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
publicclassDemo{
publicstaticvoidmain(String[] args){
InvoiceItem item1 = new InvoiceItem(
"电脑",
1,
new BigDecimal("4999.00"),
BigDecimal.ZERO,
new BigDecimal("0.13")
);
InvoiceItem item2 = new InvoiceItem(
"鼠标",
2,
new BigDecimal("59.90"),
new BigDecimal("0.10"), // 打 9 折
new BigDecimal("0.13")
);
List<InvoiceItem> items = Arrays.asList(item1, item2);
// 假设财务系统那边给的发票总额
BigDecimal invoiceTotal = new BigDecimal("5200.00");
List<InvoiceCalculator.LineAmount> list =
InvoiceCalculator.calcWithAdjust(items, invoiceTotal);
list.forEach(line -> {
System.out.println(line.item.getName() + " 行金额 = " + line.amount);
});
}
}
实际运行的时候,你会看到每一行金额都很“正常”,并且两行相加刚好是 5200.00。 如果因为四舍五入有 0.01 的误差,就会被我们塞到金额最大的那一行里去,财务看起来也完全能接受。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html