1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
| import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.umetrip.hotel.order.constants.LogSchemaOrder;
import com.umetrip.hotel.order.constants.OrderErrorCode;
import com.umetrip.hotel.order.service.dto.Result;
import com.umetrip.hotel.order.service.iface.HotelReceiptService;
import com.umetrip.hotel.order.service.iface.dto.ProducePdfRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.graphics.image.JPEGFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.springframework.stereotype.Service;
import java.awt.Color;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
public class HotelReceiptServiceImpl implements HotelReceiptService {
private PDPageContentStream contentStream;
@Override
public Result<String> producePdf(ProducePdfRequest producePdfRequest) {
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
// 创建 PDDocumentInformation 对象
PDDocumentInformation pdd = document.getDocumentInformation();
// 设置文档的作者
pdd.setAuthor("航旅纵横");
// 设置文档的标题
pdd.setTitle("航旅纵横酒店预订账单(水单)");
contentStream = new PDPageContentStream(document, page);
InputStream inFont = this.getClass().getClassLoader().getResourceAsStream("font/AlibabaPuHuiTi-3-55-Regular.ttf");
PDType0Font font = PDType0Font.load(document, inFont);
// 设置标题的字体大小
float fontSize = 15;
contentStream.setFont(font, fontSize);
// 设置标题文本
String title = "航旅纵横酒店预订账单(水单)";
float titleWidth = font.getStringWidth(title) / 1000 * fontSize;
float titleHeight = font.getFontDescriptor().getFontBoundingBox().getHeight() / 1000 * fontSize;
float startX = (page.getMediaBox().getWidth() - titleWidth) / 2;
// 从页面顶部向下50点开始
float startY = page.getMediaBox().getHeight() - titleHeight - 50;
showTextByLeft(title, "", startX, startY);
contentStream.setFont(font, 12);
List<String> titleList = Arrays.asList("酒店名称:", "订单号:", "下单时间:", "入住人:", "联系手机:", "房型:", "入住:", "离店:", "");
String checkin = producePdfRequest.getCheckin() + "(" + DateUtil.dayOfWeekEnum(DateUtil.parse(producePdfRequest.getCheckin())).toChinese() + ")";
String checkout = producePdfRequest.getCheckout() + "(" + DateUtil.dayOfWeekEnum(DateUtil.parse(producePdfRequest.getCheckout())).toChinese() + ")";
List<String> valueList = Arrays.asList(
producePdfRequest.getHotelName(),
producePdfRequest.getOrderNo(),
producePdfRequest.getOrderTime(),
producePdfRequest.getOccupant(),
producePdfRequest.getPhone(),
producePdfRequest.getRoomType(),
checkin,
checkout,
""
);
pdfTable(page, 150, 8, 2, titleList, valueList);
titleList = Arrays.asList("项目", "房费", "其他费用", "退款", "实付", "");
String actualPayment = NumberUtil.round(NumberUtil.sub(producePdfRequest.getPayAmount(), producePdfRequest.getRefundAmount()), 2).toString();
valueList = Arrays.asList(
"金额",
"RMB " + NumberUtil.round(producePdfRequest.getPayAmount(), 2),
"RMB 0.00",
"RMB " + NumberUtil.round(producePdfRequest.getRefundAmount(), 2),
"RMB " + actualPayment,
""
);
pdfTable(page, 350, 5, 2, titleList, valueList);
showTextByLeft(String.format("用户本单通过航旅纵横平台预订,发票由%s提供。", producePdfRequest.getReceiptIssuer()), "", 100, page.getMediaBox().getHeight() - 490);
showTextByLeft(String.format("客服电话%s", producePdfRequest.getReceiptTel()), "", 100, page.getMediaBox().getHeight() - 510);
InputStream logoFile = this.getClass().getClassLoader().getResourceAsStream("invoice/航旅纵横酒店.jpeg");
PDImageXObject logo = JPEGFactory.createFromStream(document, logoFile);
// 缩放因子
float logoScale = 0.4f;
contentStream.drawImage(logo, 100, page.getMediaBox().getHeight() - 560, logo.getWidth() * logoScale, logo.getHeight() * logoScale);
if (producePdfRequest.getIsStamp() == 1) {
InputStream imageFile = this.getClass().getClassLoader().getResourceAsStream("invoice/电子印章.jpeg");
PDImageXObject image = JPEGFactory.createFromStream(document, imageFile);
float scale = 0.3f;
contentStream.drawImage(image, page.getMediaBox().getWidth() - 270, page.getMediaBox().getHeight() - 670, image.getWidth() * scale, image.getHeight() * scale);
}
contentStream.close();
String file = String.format("/opt/applog/MskyLog/umehotel-order-service/航旅纵横水单%s.pdf", producePdfRequest.getOrderNo());
document.save(file);
return Result.success(file);
} catch (IOException e) {
log.error(LogSchemaOrder.ERROR_KEY_REQUEST_EXCEPTION, "producePdf", producePdfRequest, e);
return Result.fail(OrderErrorCode.SYSTEM_ERROR);
}
}
/**
* pdf表格生成
*
* @param page pdf页
* @param yStart 上边距
* @param rows 行数
* @param cols 列数
* @param titleList 固定标题
* @param valueList 动态值
* @throws IOException io
*/ private void pdfTable(PDPage page, float yStart, int rows, int cols, List<String> titleList, List<String> valueList) throws IOException {
// 开始绘制表格
float margin = 100;
// top margin
yStart = page.getMediaBox().getHeight() - yStart;
// 表格宽度
float tableWidth = page.getMediaBox().getWidth() - 2 * 100;
// 单元格高度
float rowHeight = 20f;
// 表格高度
float tableHeight = rowHeight * rows;
// 单元格宽度
float colWidth = tableWidth / (float) cols;
// 第一列单元格宽度
float firstColumnWidth = tableWidth * 20 / 100;
// 染色
List<String> stainList = Arrays.asList("酒店名称:", "订单号:", "下单时间:", "入住人:", "联系手机:", "房型:", "入住:", "离店:", "项目", "金额");
// 绘制行
for (int i = 0; i <= rows; i++) {
contentStream.moveTo(margin, yStart - i * rowHeight);
contentStream.lineTo(margin + tableWidth, yStart - i * rowHeight);
contentStream.setNonStrokingColor(Color.black);
if (stainList.contains(titleList.get(i))) {
contentStream.setNonStrokingColor(Color.gray);
}
showTextByLeft(titleList.get(i), "", margin + 5, yStart - i * rowHeight - 15);
contentStream.setNonStrokingColor(Color.black);
if (stainList.contains(valueList.get(i))) {
contentStream.setNonStrokingColor(Color.gray);
}
showTextByLeft(valueList.get(i), "", margin + firstColumnWidth + 5, yStart - i * rowHeight - 15);
}
// 绘制列
for (int i = 0; i <= cols; i++) {
float colWidthSpe = colWidth;
if (i == 1) {
colWidthSpe = firstColumnWidth;
}
contentStream.moveTo(margin + i * colWidthSpe, yStart);
contentStream.lineTo(margin + i * colWidthSpe, yStart - tableHeight);
}
contentStream.stroke();
}
/**
* 文本添加
*
* @param txt 添加文本
* @param def 默认文本
* @param x x轴
* @param y y轴
* @throws IOException IOException
*/ private void showTextByLeft(String txt, String def, float x, float y) throws IOException {
// Begin the Content stream
contentStream.beginText();
// contentStream.setWordSpacing(0.01F);
if (null == txt) {
txt = def;
}
// Setting the position for the line
contentStream.newLineAtOffset(x, y);
// Adding text in the form of string
contentStream.showText(txt);
// Ending the content stream
contentStream.endText();
}
}
|