|
|
|
@ -11,8 +11,6 @@ import model.OutboundRecord;
|
|
|
|
|
import model.DataManager;
|
|
|
|
|
import model.Goods;
|
|
|
|
|
import javafx.collections.FXCollections;
|
|
|
|
|
import model.InboundRecord;
|
|
|
|
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
import java.sql.*;
|
|
|
|
@ -20,7 +18,7 @@ import java.sql.*;
|
|
|
|
|
public class OutboundView extends BorderPane {
|
|
|
|
|
|
|
|
|
|
private TextField goodsField;
|
|
|
|
|
private TextField supplierField;
|
|
|
|
|
private TextField customerField;
|
|
|
|
|
private TextField quantityField;
|
|
|
|
|
private TextField remarkField;
|
|
|
|
|
private TableView<OutboundRecord> tableView;
|
|
|
|
@ -49,20 +47,21 @@ public class OutboundView extends BorderPane {
|
|
|
|
|
VBox topArea = new VBox(10);
|
|
|
|
|
topArea.setPadding(new Insets(10));
|
|
|
|
|
|
|
|
|
|
// 第一行:基本信息
|
|
|
|
|
// 基本信息
|
|
|
|
|
GridPane basicInfo = new GridPane();
|
|
|
|
|
basicInfo.setHgap(10);
|
|
|
|
|
basicInfo.setVgap(10);
|
|
|
|
|
|
|
|
|
|
// 第一行:货物名称和供应商
|
|
|
|
|
Label goodsLabel = new Label("货物名称:");
|
|
|
|
|
goodsField = new TextField();
|
|
|
|
|
goodsField.setPromptText("请输入货物名称");
|
|
|
|
|
|
|
|
|
|
Label supplierLabel = new Label("供应商:");
|
|
|
|
|
supplierField = new TextField();
|
|
|
|
|
supplierField.setPromptText("请输入供应商");
|
|
|
|
|
customerField = new TextField();
|
|
|
|
|
customerField.setPromptText("请输入供应商");
|
|
|
|
|
|
|
|
|
|
basicInfo.addRow(0, goodsLabel, goodsField, supplierLabel, supplierField);
|
|
|
|
|
basicInfo.addRow(0, goodsLabel, goodsField, supplierLabel, customerField);
|
|
|
|
|
|
|
|
|
|
// 第二行:数量和备注
|
|
|
|
|
Label quantityLabel = new Label("数量:");
|
|
|
|
@ -92,7 +91,7 @@ public class OutboundView extends BorderPane {
|
|
|
|
|
buttonBox.setAlignment(Pos.CENTER_RIGHT);
|
|
|
|
|
buttonBox.setPadding(new Insets(10, 0, 0, 0));
|
|
|
|
|
|
|
|
|
|
Button saveButton = new Button("保存");
|
|
|
|
|
Button saveButton = new Button("出库");
|
|
|
|
|
saveButton.setOnAction(e -> handleSave());
|
|
|
|
|
|
|
|
|
|
Button clearButton = new Button("清空");
|
|
|
|
@ -107,32 +106,57 @@ public class OutboundView extends BorderPane {
|
|
|
|
|
private TableView<OutboundRecord> createTableView() {
|
|
|
|
|
TableView<OutboundRecord> table = new TableView<>();
|
|
|
|
|
|
|
|
|
|
TableColumn<OutboundRecord, String> idCol = new TableColumn<>("出库单号");
|
|
|
|
|
TableColumn<OutboundRecord, String> idCol = new TableColumn<>("单号");
|
|
|
|
|
idCol.setCellValueFactory(new PropertyValueFactory<>("id"));
|
|
|
|
|
idCol.setPrefWidth(150);
|
|
|
|
|
|
|
|
|
|
TableColumn<OutboundRecord, String> goodsCol = new TableColumn<>("货物名称");
|
|
|
|
|
goodsCol.setCellValueFactory(new PropertyValueFactory<>("goodsId"));
|
|
|
|
|
goodsCol.setPrefWidth(120);
|
|
|
|
|
|
|
|
|
|
TableColumn<OutboundRecord, Integer> quantityCol = new TableColumn<>("数量");
|
|
|
|
|
quantityCol.setCellValueFactory(new PropertyValueFactory<>("quantity"));
|
|
|
|
|
quantityCol.setPrefWidth(80);
|
|
|
|
|
|
|
|
|
|
TableColumn<OutboundRecord, String> supplierCol = new TableColumn<>("供应商");
|
|
|
|
|
supplierCol.setCellValueFactory(new PropertyValueFactory<>("supplier"));
|
|
|
|
|
TableColumn<OutboundRecord, String> customerCol = new TableColumn<>("供应商");
|
|
|
|
|
customerCol.setCellValueFactory(new PropertyValueFactory<>("customer"));
|
|
|
|
|
customerCol.setPrefWidth(120);
|
|
|
|
|
|
|
|
|
|
TableColumn<OutboundRecord, LocalDateTime> timeCol = new TableColumn<>("出库时间");
|
|
|
|
|
timeCol.setCellValueFactory(new PropertyValueFactory<>("inboundTime")); // 保持字段名不变,但实际表示出库时间
|
|
|
|
|
timeCol.setCellValueFactory(new PropertyValueFactory<>("outboundTime"));
|
|
|
|
|
timeCol.setPrefWidth(180);
|
|
|
|
|
timeCol.setCellFactory(column -> new TableCell<OutboundRecord, LocalDateTime>() {
|
|
|
|
|
private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
|
|
|
|
@Override
|
|
|
|
|
protected void updateItem(LocalDateTime item, boolean empty) {
|
|
|
|
|
super.updateItem(item, empty);
|
|
|
|
|
if (empty || item == null) {
|
|
|
|
|
setText(null);
|
|
|
|
|
} else {
|
|
|
|
|
setText(formatter.format(item));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
TableColumn<OutboundRecord, String> operatorCol = new TableColumn<>("操作员");
|
|
|
|
|
operatorCol.setCellValueFactory(new PropertyValueFactory<>("operator"));
|
|
|
|
|
operatorCol.setPrefWidth(100);
|
|
|
|
|
|
|
|
|
|
TableColumn<OutboundRecord, String> remarkCol = new TableColumn<>("备注");
|
|
|
|
|
remarkCol.setCellValueFactory(new PropertyValueFactory<>("remark"));
|
|
|
|
|
remarkCol.setPrefWidth(150);
|
|
|
|
|
|
|
|
|
|
table.getColumns().addAll(idCol, goodsCol, quantityCol, supplierCol,
|
|
|
|
|
table.getColumns().addAll(idCol, goodsCol, quantityCol, customerCol,
|
|
|
|
|
timeCol, operatorCol, remarkCol);
|
|
|
|
|
|
|
|
|
|
table.getItems().addListener((javafx.collections.ListChangeListener.Change<? extends OutboundRecord> c) -> {
|
|
|
|
|
updateTotal();
|
|
|
|
|
// 添加双击事件处理
|
|
|
|
|
table.setOnMouseClicked(event -> {
|
|
|
|
|
if (event.getClickCount() == 2) {
|
|
|
|
|
OutboundRecord selectedRecord = table.getSelectionModel().getSelectedItem();
|
|
|
|
|
if (selectedRecord != null) {
|
|
|
|
|
fillFields(selectedRecord);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return table;
|
|
|
|
@ -161,98 +185,89 @@ public class OutboundView extends BorderPane {
|
|
|
|
|
private void handleSave() {
|
|
|
|
|
try {
|
|
|
|
|
String goodsName = goodsField.getText().trim();
|
|
|
|
|
String supplier = supplierField.getText().trim();
|
|
|
|
|
String customer = customerField.getText().trim();
|
|
|
|
|
String quantityText = quantityField.getText().trim();
|
|
|
|
|
String remark = remarkField.getText().trim();
|
|
|
|
|
|
|
|
|
|
// 输入验证
|
|
|
|
|
if (goodsName.isEmpty() || supplier.isEmpty() || quantityText.isEmpty()) {
|
|
|
|
|
if (goodsName.isEmpty() || customer.isEmpty() || quantityText.isEmpty()) {
|
|
|
|
|
showAlert("错误", "请填写完整的出库信息!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int quantity;
|
|
|
|
|
try {
|
|
|
|
|
quantity = Integer.parseInt(quantityText);
|
|
|
|
|
if (quantity <= 0) {
|
|
|
|
|
showAlert("错误", "数量必须大于0!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
showAlert("错误", "请输入有效的数量!");
|
|
|
|
|
int quantity = Integer.parseInt(quantityText);
|
|
|
|
|
if (quantity <= 0) {
|
|
|
|
|
showAlert("错误", "数量必须大于0!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 检查库存是否足够
|
|
|
|
|
if (!isStockSufficient(goodsName, quantity)) {
|
|
|
|
|
showAlert("错误", "库存不足!");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建出库记录
|
|
|
|
|
String id = "OUT" + System.currentTimeMillis();
|
|
|
|
|
LocalDateTime now = LocalDateTime.now();
|
|
|
|
|
|
|
|
|
|
// 修改数据库连接为相对路径
|
|
|
|
|
String url = "jdbc:sqlite:db/dbuml.db3";
|
|
|
|
|
try (Connection conn = DriverManager.getConnection(url)) {
|
|
|
|
|
String sql = "INSERT INTO warehouse (id, goods_id, quantity, supplier, inbound_time, operator, remark, type) " +
|
|
|
|
|
"VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
|
|
|
|
|
|
|
|
|
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
|
|
|
|
|
pstmt.setString(1, id);
|
|
|
|
|
pstmt.setString(2, goodsName);
|
|
|
|
|
pstmt.setInt(3, quantity);
|
|
|
|
|
pstmt.setString(4, supplier);
|
|
|
|
|
pstmt.setString(5, now.toString());
|
|
|
|
|
pstmt.setString(6, "当前用户");
|
|
|
|
|
pstmt.setString(7, remark);
|
|
|
|
|
pstmt.setString(8, "OUT"); // 设置类型为出库
|
|
|
|
|
|
|
|
|
|
pstmt.executeUpdate();
|
|
|
|
|
// 首先查询当前库存
|
|
|
|
|
String checkSql = "SELECT id, quantity FROM warehouse WHERE goods_id = ?";
|
|
|
|
|
try (PreparedStatement checkStmt = conn.prepareStatement(checkSql)) {
|
|
|
|
|
checkStmt.setString(1, goodsName);
|
|
|
|
|
ResultSet rs = checkStmt.executeQuery();
|
|
|
|
|
|
|
|
|
|
if (rs.next()) {
|
|
|
|
|
int currentStock = rs.getInt("quantity");
|
|
|
|
|
String recordId = rs.getString("id");
|
|
|
|
|
|
|
|
|
|
if (currentStock < quantity) {
|
|
|
|
|
showAlert("错误", "库存不足!当前库存: " + currentStock);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int remainingStock = currentStock - quantity;
|
|
|
|
|
|
|
|
|
|
if (remainingStock == 0) {
|
|
|
|
|
// 如果全部出库,删除记录
|
|
|
|
|
String deleteSql = "DELETE FROM warehouse WHERE id = ?";
|
|
|
|
|
try (PreparedStatement deleteStmt = conn.prepareStatement(deleteSql)) {
|
|
|
|
|
deleteStmt.setString(1, recordId);
|
|
|
|
|
deleteStmt.executeUpdate();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 更新剩余库存
|
|
|
|
|
String updateSql = "UPDATE warehouse SET quantity = ? WHERE id = ?";
|
|
|
|
|
try (PreparedStatement updateStmt = conn.prepareStatement(updateSql)) {
|
|
|
|
|
updateStmt.setInt(1, remainingStock);
|
|
|
|
|
updateStmt.setString(2, recordId);
|
|
|
|
|
updateStmt.executeUpdate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 刷新表格显示
|
|
|
|
|
loadOutboundRecords();
|
|
|
|
|
|
|
|
|
|
// 清空输入
|
|
|
|
|
handleClear();
|
|
|
|
|
|
|
|
|
|
// 添加操作日志
|
|
|
|
|
String details = String.format("出库货物:%s,数量:%d,供应商:%s",
|
|
|
|
|
goodsName, quantity, customer);
|
|
|
|
|
DataManager.getInstance().addOperationLog("出库", goodsName, "当前用户", details);
|
|
|
|
|
|
|
|
|
|
showAlert("成功", "出库记录已保存!");
|
|
|
|
|
} else {
|
|
|
|
|
showAlert("错误", "未找到该货物的库存记录!");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建记录对象并添加到表格
|
|
|
|
|
OutboundRecord record = new OutboundRecord(
|
|
|
|
|
id,
|
|
|
|
|
goodsName,
|
|
|
|
|
quantity,
|
|
|
|
|
supplier,
|
|
|
|
|
now,
|
|
|
|
|
"当前用户",
|
|
|
|
|
remark
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// 添加到表格
|
|
|
|
|
tableView.getItems().add(record);
|
|
|
|
|
|
|
|
|
|
// 更新总计
|
|
|
|
|
updateTotal();
|
|
|
|
|
|
|
|
|
|
// 清空输入
|
|
|
|
|
handleClear();
|
|
|
|
|
|
|
|
|
|
// 添加操作日志
|
|
|
|
|
String details = String.format("出库货物:%s,数量:%d,供应商:%s",
|
|
|
|
|
goodsName, quantity, supplier);
|
|
|
|
|
DataManager.getInstance().addOperationLog("出库", goodsName, "当前用户", details);
|
|
|
|
|
|
|
|
|
|
showAlert("成功", "出库记录已保存!");
|
|
|
|
|
|
|
|
|
|
} catch (NumberFormatException e) {
|
|
|
|
|
showAlert("错误", "请输入有效的数量!");
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
showAlert("错误", "保存失败:" + e.getMessage());
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
showAlert("错误", "保存失败:" + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void handleClear() {
|
|
|
|
|
goodsField.clear();
|
|
|
|
|
supplierField.clear();
|
|
|
|
|
customerField.clear();
|
|
|
|
|
quantityField.clear();
|
|
|
|
|
remarkField.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void showAlert(String title, String content) {
|
|
|
|
|
Alert alert = new Alert(Alert.AlertType.INFORMATION);
|
|
|
|
|
alert.setTitle(title);
|
|
|
|
@ -261,26 +276,42 @@ public class OutboundView extends BorderPane {
|
|
|
|
|
alert.showAndWait();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 添加加载数据的方法
|
|
|
|
|
private void loadOutboundRecords() {
|
|
|
|
|
String url = "jdbc:sqlite:db/dbuml.db3";
|
|
|
|
|
try (Connection conn = DriverManager.getConnection(url)) {
|
|
|
|
|
String sql = "SELECT * FROM warehouse WHERE type = 'OUT' ORDER BY inbound_time DESC";
|
|
|
|
|
String sql = "SELECT * FROM warehouse ORDER BY inbound_time DESC";
|
|
|
|
|
try (Statement stmt = conn.createStatement();
|
|
|
|
|
ResultSet rs = stmt.executeQuery(sql)) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tableView.getItems().clear();
|
|
|
|
|
while (rs.next()) {
|
|
|
|
|
OutboundRecord record = new OutboundRecord(
|
|
|
|
|
rs.getString("id"),
|
|
|
|
|
rs.getString("goods_id"),
|
|
|
|
|
rs.getInt("quantity"),
|
|
|
|
|
rs.getString("supplier"),
|
|
|
|
|
LocalDateTime.parse(rs.getString("inbound_time")), // 实际表示出库时间
|
|
|
|
|
rs.getString("operator"),
|
|
|
|
|
rs.getString("remark")
|
|
|
|
|
);
|
|
|
|
|
tableView.getItems().add(record);
|
|
|
|
|
try {
|
|
|
|
|
String id = rs.getString("id");
|
|
|
|
|
String goodsId = rs.getString("goods_id");
|
|
|
|
|
int quantity = rs.getInt("quantity");
|
|
|
|
|
String supplier = rs.getString("supplier");
|
|
|
|
|
String timeStr = rs.getString("inbound_time");
|
|
|
|
|
String operator = rs.getString("operator");
|
|
|
|
|
String remark = rs.getString("remark");
|
|
|
|
|
|
|
|
|
|
LocalDateTime dateTime = LocalDateTime.parse(timeStr);
|
|
|
|
|
|
|
|
|
|
OutboundRecord record = new OutboundRecord(
|
|
|
|
|
id,
|
|
|
|
|
goodsId,
|
|
|
|
|
quantity,
|
|
|
|
|
supplier,
|
|
|
|
|
dateTime,
|
|
|
|
|
operator,
|
|
|
|
|
remark
|
|
|
|
|
);
|
|
|
|
|
tableView.getItems().add(record);
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
updateTotal();
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
@ -288,24 +319,11 @@ public class OutboundView extends BorderPane {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 查询库存是否足够
|
|
|
|
|
private boolean isStockSufficient(String goodsName, int quantity) {
|
|
|
|
|
String url = "jdbc:sqlite:db/dbuml.db3";
|
|
|
|
|
try (Connection conn = DriverManager.getConnection(url)) {
|
|
|
|
|
String sql = "SELECT SUM(quantity) AS total_stock FROM warehouse WHERE goods_id = ? AND type = 'IN'";
|
|
|
|
|
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
|
|
|
|
|
pstmt.setString(1, goodsName);
|
|
|
|
|
try (ResultSet rs = pstmt.executeQuery()) {
|
|
|
|
|
if (rs.next()) {
|
|
|
|
|
int totalStock = rs.getInt("total_stock");
|
|
|
|
|
return totalStock >= quantity;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (SQLException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
showAlert("错误", "查询库存失败:" + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
return false; // 默认返回false,防止未知错误导致库存检查失败
|
|
|
|
|
// <20><>加填充字段的方法
|
|
|
|
|
private void fillFields(OutboundRecord record) {
|
|
|
|
|
goodsField.setText(record.getGoodsId());
|
|
|
|
|
customerField.setText(record.getCustomer());
|
|
|
|
|
quantityField.setText(String.valueOf(record.getQuantity()));
|
|
|
|
|
remarkField.setText(record.getRemark());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|