Archived
0
This commit is contained in:
2018-07-18 18:17:14 +03:00
parent cd2b55fce8
commit 61d4897720
13 changed files with 464 additions and 698 deletions

View File

@@ -1,39 +1,28 @@
package ru.dmitriymx.corrector1s; package ru.dmitriymx.corrector1s;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference; import org.xml.sax.SAXException;
import ru.dmitriymx.corrector1s.config.ColumnData;
import ru.dmitriymx.corrector1s.config.XmlConfig;
import ru.dmitriymx.corrector1s.excel.ExcelDocument;
import ru.dmitriymx.corrector1s.excel.ExcelRecord;
import ru.dmitriymx.corrector1s.excel.ExcelRecordData;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@Slf4j
@NoArgsConstructor
public class Corrector1S { public class Corrector1S {
private class ExcelRecord {
private String name;
private Integer addition;
private List<Double> dataList;
ExcelRecord(int capacity) {
dataList = new ArrayList<>(capacity);
}
boolean isEmptyDataList() {
return dataList.stream().mapToDouble(Double::doubleValue).sum() == 0.0d;
}
}
@Setter @Setter
private File sourceFile; private File sourceFile;
@Setter @Setter
@@ -44,16 +33,11 @@ public class Corrector1S {
private double fss; private double fss;
private Map<String, ExcelRecord> mapRecords; private Map<String, ExcelRecord> mapRecords;
private Workbook workbook; private ExcelDocument document;
private Sheet sheet;
/** номер колонки "Итого начислено" */ private String buildKeyRecord(String title, Object addon) {
private int cellNumSum = 0; return title.trim() + (Utils.isEmptyObject(addon) ? "" : "_" + addon.toString());
/** номер колонки с больничными */ }
private int cellBol = 0;
/** последняя колонка в исходном документе */
private int lastColumn = 0;
private CellStyle cellStyle1, cellStyle2;
private int maxLines = 0;
private String getFileExtension(File file) { private String getFileExtension(File file) {
int i = file.getAbsolutePath().lastIndexOf('.'); int i = file.getAbsolutePath().lastIndexOf('.');
@@ -64,11 +48,13 @@ public class Corrector1S {
} }
} }
private String buildSumFormula(int column, int startLine, int endLine) { /**
String columnChar = CellReference.convertNumToColString(column); * Проверяем входные параметры и формат файла
return String.format("SUM(%s%d:%s%d)", columnChar, startLine+1, columnChar, endLine+1); * @throws Exception
} * {@link AssertionError} - если ошибка во входных параметрах;
* {@link FileNotFoundException} - если входной вайл не найден;
* {@link FormatFileException} - если данные в Excel не соответствуют ожиданиям.
*/
public void check() throws Exception { public void check() throws Exception {
if (honorarium == 0.0d) throw new AssertionError("Honorarium not be 0.0%!"); if (honorarium == 0.0d) throw new AssertionError("Honorarium not be 0.0%!");
if (fss == 0.0d) throw new AssertionError("FSS not be 0.0%!"); if (fss == 0.0d) throw new AssertionError("FSS not be 0.0%!");
@@ -80,329 +66,73 @@ public class Corrector1S {
if (targetFile == null) throw new AssertionError("Target file not be null!"); if (targetFile == null) throw new AssertionError("Target file not be null!");
Workbook workbook = WorkbookFactory.create(sourceFile); try (Workbook workbook = WorkbookFactory.create(sourceFile)) {
Sheet sheet = workbook.getSheetAt(0); Sheet sheet = workbook.getSheetAt(0);
try {
sheet.getRow(6).getCell(8); sheet.getRow(6).getCell(8);
sheet.getRow(7).getCell(8); sheet.getRow(7).getCell(8);
sheet.getRow(8).getCell(8); sheet.getRow(8).getCell(8);
} catch (Exception e) { } catch (Exception e) {
workbook.close();
throw new FormatFileException(e); throw new FormatFileException(e);
} }
// get max lines
for (int line = 8; true; line++) {
if (sheet.getRow(line) == null) {
this.maxLines = line - 2;
break;
}
}
workbook.close();
} }
/**
* Сохраняем данные по всем колонкам
*/
public void createSnapshotData() throws IOException, InvalidFormatException { public void createSnapshotData() throws IOException, InvalidFormatException {
workbook = WorkbookFactory.create(sourceFile); this.document = new ExcelDocument(this.sourceFile);
sheet = workbook.getSheetAt(0); this.mapRecords = new HashMap<>(this.document.getMaxColumn() - ExcelDocument.START_COLUMN);
mapRecords = new HashMap<>(20);
Cell cell; for (int column = ExcelDocument.START_COLUMN; column <= this.document.getMaxColumn(); column++) {
loop: ExcelRecordData record = this.document.getColumnRecord(column);
for (int column = 8; true; column++) { String key = buildKeyRecord(record.getTitle(), record.getAddon());
ExcelRecord record = new ExcelRecord(this.maxLines);
for (int line = 6; line <= this.maxLines; line++) { this.mapRecords.put(key, record);
cell = sheet.getRow(line).getCell(column);
if (cell == null) break loop;
if (line == 6) {
record.name = cell.getStringCellValue();
} else if (line == 7) {
if (cell.getCellTypeEnum().equals(CellType.NUMERIC)) {
record.addition = (int) cell.getNumericCellValue();
} else {
record.addition = 0;
}
} else {
record.dataList.add(cell.getNumericCellValue());
}
}
String key = (record.addition == 0 ? record.name.trim() : record.name.trim() + "_" + record.addition);
mapRecords.put(key, record);
} }
} }
/**
* Убираем объединение ячеек
*/
public void removeMergedCells() { public void removeMergedCells() {
while (sheet.getNumMergedRegions() > 5) { /*
for(int m = 0; m < sheet.getNumMergedRegions(); m++) { Опытным путём было выявлено, что должно остаться 5 объединённых регионов, если у всех остальных колонок
CellRangeAddress cellRangeAddress = sheet.getMergedRegion(m); убрать объединение.
*/
while (this.document.getNumMergedCells() > 5) {
for(int m = 0; m < this.document.getNumMergedCells(); m++) {
CellRangeAddress cellRangeAddress = this.document.getMergedCells(m);
if (cellRangeAddress.getFirstColumn() >= 8) { if (cellRangeAddress.getFirstColumn() >= 8) {
sheet.removeMergedRegion(m); this.document.removeMergedCells(m);
break; break;
} }
} }
} }
} }
private void setCellRecord(ExcelRecord record, int column) { /**
// NAME * Производим сортировку колонок (по сути переписывая текущие значения)
Cell cell = sheet.getRow(6).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); */
cell.setCellType(CellType.STRING);
cell.setCellValue(record.name);
// ADDITION
cell = sheet.getRow(7).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
if (record.addition == 0) {
cell.setCellType(CellType.BLANK);
} else {
cell.setCellType(CellType.NUMERIC);
cell.setCellValue(record.addition);
}
// DATA
for (int line = 8; line <= this.maxLines; line++) {
cell = sheet.getRow(line).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
double data = record.dataList.get(line-8);
if (data == 0) {
cell.setCellType(CellType.BLANK);
} else {
cell.setCellType(CellType.NUMERIC);
cell.setCellValue(data);
}
}
// SUM
cell = sheet.getRow(this.maxLines+1).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
if (record.isEmptyDataList()) {
cell.setCellType(CellType.BLANK);
} else {
cell.setCellType(CellType.FORMULA);
cell.setCellFormula(buildSumFormula(column, 8, this.maxLines));
}
}
public void replaceData() { public void replaceData() {
int column = 8; XmlConfig config = null;
ExcelRecord record; try {
if ((record = mapRecords.remove("Отпуск очередной_104")) != null) setCellRecord(record, column++); config = new XmlConfig(new File("config.xml"));
if ((record = mapRecords.remove("Больничный за счет работодателя_105")) != null) { } catch (ParserConfigurationException | IOException | SAXException e) {
setCellRecord(record, column++); e.printStackTrace(); //FIXME логирование ошибки
this.cellBol = column-1;
} }
if ((record = mapRecords.remove("Дневные")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("Ночные")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("Ночные_123")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("питание_124")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("Выходные")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("выходные_135")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("пересчет за прошлый месяц_141")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("вредность_145")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("Материальная помощь при рождении ребенка_148")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("компенсация за задержку зарплаты_169")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("Оплата по среднему (донорство, посещение врача)_174")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("Компенсация проезда при использовании личного транспорта_176")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("сверхурочные_133")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("Сверхурочные 1.5 ставки")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("сверхурочные 1,5_180")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("Сверхурочные 2 ставки")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("сверхурочные 2_181")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("Компенсация за неиспользованный отпуск (с декабря 2017)_184")) != null) setCellRecord(record, column++);
if ((record = mapRecords.remove("Месячная премия 2018_186")) != null) setCellRecord(record, column++);
if (mapRecords.size() > 1) { List<ColumnData> columnDataList = config.getColumnDataList();
for (ExcelRecord rec : mapRecords.values()) { Iterator<ColumnData> itrColumnDataList = columnDataList.iterator();
if (!rec.name.equalsIgnoreCase("Итого начислено")) { for (int column = ExcelDocument.START_COLUMN; column <= document.getMaxColumn(); column++) {
setCellRecord(rec, column++); if (itrColumnDataList.hasNext()) {
ColumnData columnData = itrColumnDataList.next();
ExcelRecord record = mapRecords.remove(buildKeyRecord(columnData.getTitle(), columnData.getAddon()));
if (record == null) continue; //FIXME логирование отсутствия нужной колонки
this.document.setColumnRecord(column, record);
//TODO не забываем, нужно еще составить мапу id-column для дальнейшей генерации формул
} }
} }
} }
if ((record = mapRecords.remove("Итого начислено")) != null) setCellRecord(record, column++);
cellNumSum = column-1;
this.lastColumn = column;
}
private void initStyle() {
Font font = workbook.createFont();
font.setFontName("Arial");
font.setBold(true);
font.setFontHeightInPoints((short) 8);
cellStyle1 = workbook.createCellStyle();
cellStyle1.setAlignment(HorizontalAlignment.CENTER);
cellStyle1.setVerticalAlignment(VerticalAlignment.CENTER);
cellStyle1.setFont(font);
cellStyle1.setWrapText(true);
cellStyle1.setBorderTop(BorderStyle.THIN);
cellStyle1.setBorderBottom(BorderStyle.THIN);
cellStyle1.setBorderLeft(BorderStyle.THIN);
cellStyle1.setBorderRight(BorderStyle.THIN);
cellStyle2 = workbook.createCellStyle();
cellStyle2.setBorderTop(BorderStyle.THIN);
cellStyle2.setBorderBottom(BorderStyle.THIN);
cellStyle2.setBorderLeft(BorderStyle.THIN);
cellStyle2.setBorderRight(BorderStyle.THIN);
}
private void insertCell(String title, String addition, String formulaTemplate, String formulaSum, int column) {
// NAME
Cell cell = sheet.getRow(6).createCell(column);
cell.setCellType(CellType.STRING);
cell.setCellValue(title);
cell.setCellStyle(cellStyle1);
// ADDITION
cell = sheet.getRow(7).createCell(column);
cell.setCellType(CellType.STRING);
cell.setCellValue(addition);
cell.setCellStyle(cellStyle1);
// DATA
for (int line = 8; line <= this.maxLines; line++) {
cell = sheet.getRow(line).createCell(column);
cell.setCellStyle(cellStyle2);
cell.setCellType(CellType.FORMULA);
cell.setCellFormula(formulaTemplate.replace("{L}", String.valueOf(line+1)).replace(',','.'));
}
// SUM
cell = sheet.getRow(this.maxLines+1).createCell(column);
cell.setCellStyle(cellStyle2);
cell.setCellType(CellType.FORMULA);
cell.setCellFormula(formulaSum);
}
public void insertNewCols() {
initStyle();
int column = lastColumn;
// FSS
String formulaTemplate;
if (cellBol == 0) {
formulaTemplate = String.format(
"(%s{L})*%.2f%%",
CellReference.convertNumToColString(cellNumSum),
this.fss
);
} else {
formulaTemplate = String.format(
"(%s{L}-%s{L})*%.2f%%",
CellReference.convertNumToColString(cellNumSum),
CellReference.convertNumToColString(cellBol),
this.fss
);
}
insertCell(
String.format("Страховые взносы + ФСС НС (%.2f%%)", this.fss),
"Начислено",
formulaTemplate,
buildSumFormula(column, 8, this.maxLines),
column++
);
// BASE
insertCell(
"БАЗА",
"для начисления стоимости услуг",
String.format("%s{L}+%s{L}",
CellReference.convertNumToColString(cellNumSum),
CellReference.convertNumToColString(column-1)),
buildSumFormula(column, 8, this.maxLines),
column++
);
// HONORARIUM
insertCell(
"Гонорар",
String.format("%.2f%%", this.honorarium),
String.format("%s{L}*%.2f%%",
CellReference.convertNumToColString(column-1),
this.honorarium),
buildSumFormula(column, 8, this.maxLines),
column++
);
// SUM ALL
insertCell(
"Итого, для счета",
"Результат",
String.format("%s{L}+%s{L}",
CellReference.convertNumToColString(column-2),
CellReference.convertNumToColString(column-1)),
buildSumFormula(column, 8, this.maxLines),
column
);
}
public void insertNewLines() {
int line = maxLines+3;
int t1 = line;
Cell cell = sheet.createRow(line).getCell(2, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.STRING);
cell.setCellValue("Итого по справке:");
cell = sheet.getRow(line++).getCell(6, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.FORMULA);
cell.setCellFormula(String.format("%s%d", CellReference.convertNumToColString(this.lastColumn+3), this.maxLines+2));
cell = sheet.createRow(line++).getCell(2, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.STRING);
cell.setCellValue("Дополнительные страховые взносы за сварщиков");
cell = sheet.createRow(line++).getCell(2, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.STRING);
cell.setCellValue("Корпоративный транспорт");
cell = sheet.createRow(line++).getCell(2, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.STRING);
cell.setCellValue("Подбор персонала сторонним агентством");
cell = sheet.createRow(line++).getCell(2, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.STRING);
cell.setCellValue("Страхование жизни");
cell = sheet.createRow(line++).getCell(2, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.STRING);
cell.setCellValue("Страхование НС");
int t2 = line;
cell = sheet.createRow(line).getCell(2, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.STRING);
cell.setCellValue("Итого без НДС");
cell = sheet.getRow(line++).getCell(6, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.FORMULA);
cell.setCellFormula(String.format("%s%d", CellReference.convertNumToColString(6), t1+1));
int t3 = line;
cell = sheet.createRow(line).getCell(2, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.STRING);
cell.setCellValue("Сумма НДС:");
cell = sheet.getRow(line++).getCell(6, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.FORMULA);
cell.setCellFormula(String.format("%s%d*18%%", CellReference.convertNumToColString(6), t2+1));
cell = sheet.createRow(line).getCell(2, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.STRING);
cell.setCellValue("Всего (с учетом НДС):");
cell = sheet.getRow(line).getCell(6, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.FORMULA);
cell.setCellFormula(String.format("%s%d+%s%d",
CellReference.convertNumToColString(6),
t2+1,
CellReference.convertNumToColString(6),
t3+1));
}
public void saveFile() throws IOException {
workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
try (FileOutputStream fos = new FileOutputStream(targetFile)) {
workbook.write(fos);
workbook.close();
}
}
} }

View File

@@ -1,97 +0,0 @@
package ru.dmitriymx.corrector1s;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
import lombok.extern.slf4j.Slf4j;
import ru.dmitriymx.corrector1s.gui.MainApp;
import java.io.File;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
@Slf4j
public class Main {
public static final String VERSION = "1.0.5";
private static OptionParser buildOptionParser() {
final OptionParser optionParser = new OptionParser();
optionParser.acceptsAll(Arrays.asList("s", "source"), "Source Excel file")
.withRequiredArg()
.ofType(File.class)
.required();
optionParser.acceptsAll(Arrays.asList("t", "target"), "Target Excel file (default: target = source)")
.withRequiredArg()
.ofType(File.class);
optionParser.acceptsAll(Arrays.asList("h", "honorarium"), "Honorarium (in percentages)")
.withRequiredArg()
.ofType(Double.class)
.defaultsTo(9.0d);
optionParser.acceptsAll(Arrays.asList("f", "fss"), "FSS (in percentages)")
.withRequiredArg()
.ofType(Double.class)
.defaultsTo(31.0d);
optionParser.acceptsAll(Arrays.asList("h", "help"), "Help page. Display this message")
.forHelp();
optionParser.acceptsAll(Arrays.asList("v", "version"), "Version")
.forHelp();
return optionParser;
}
public static void main(String[] args) throws Exception {
if (args.length == 0) {
MainApp.main(args);
} else {
OptionParser parser = buildOptionParser();
OptionSet optionSet;
try {
optionSet = parser.parse(args);
} catch (joptsimple.OptionException e) {
if (e.getMessage().contains("Missing")) {
log.error(e.getMessage());
} else {
log.error("", e);
}
return;
}
if (optionSet.has("help")) {
System.out.printf("Version: %s\n", VERSION);
parser.printHelpOn(System.out);
return;
} else if (optionSet.has("version")) {
System.out.printf("Version: %s\n", VERSION);
return;
}
File sourceFile, targetFile;
sourceFile = (File) optionSet.valueOf("source");
if (optionSet.has("target")) {
targetFile = (File) optionSet.valueOf("target");
} else {
targetFile = sourceFile;
}
log.debug("Source file: {} (exists: {})", sourceFile.getAbsolutePath(), Files.exists(sourceFile.toPath()));
log.debug("Target file: {}", targetFile.getAbsolutePath());
log.debug("Honorarium: {}%", optionSet.valueOf("honorarium"));
log.debug("FSS: {}%", optionSet.valueOf("fss"));
Corrector1S corrector1S = new Corrector1S();
corrector1S.setSourceFile(sourceFile);
corrector1S.setTargetFile(targetFile);
corrector1S.setHonorarium((Double) optionSet.valueOf("honorarium"));
corrector1S.setFss((Double) optionSet.valueOf("fss"));
corrector1S.check();
corrector1S.createSnapshotData();
corrector1S.removeMergedCells();
corrector1S.replaceData();
corrector1S.insertNewCols();
corrector1S.insertNewLines();
corrector1S.saveFile();
}
}
}

View File

@@ -0,0 +1,15 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-07-18
*/
package ru.dmitriymx.corrector1s;
public class Utils {
public static boolean isEmptyObject(Object obj) {
if (obj instanceof Number) {
return (Integer) obj == 0;
} else {
return obj == null || obj.toString().trim().isEmpty();
}
}
}

View File

@@ -0,0 +1,16 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-07-18
*/
package ru.dmitriymx.corrector1s.config;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class ColumnData {
private String title;
private String addon;
private String id;
}

View File

@@ -0,0 +1,75 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-07-18
*/
package ru.dmitriymx.corrector1s.config;
import jdk.nashorn.internal.runtime.regexp.joni.constants.NodeType;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class XmlConfig {
private Document document;
private Node rootNode;
private DocumentBuilder init() throws ParserConfigurationException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
return dbf.newDocumentBuilder();
}
public XmlConfig(File file) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilder db = init();
this.document = db.parse(file);
this.rootNode = this.document.getChildNodes().item(0);
}
public XmlConfig(InputStream inputStream) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilder db = init();
this.document = db.parse(inputStream);
this.rootNode = this.document.getChildNodes().item(0);
}
public List<ColumnData> getColumnDataList() {
NodeList childNodes = this.rootNode.getChildNodes().item(/*columns*/1).getChildNodes();
List<ColumnData> result = new ArrayList<>((childNodes.getLength()-1)/2);
for(int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node.getNodeType() == NodeType.CCLASS) {
ColumnData columnData = new ColumnData();
Node attrTitle = node.getAttributes().getNamedItem("title");
if (attrTitle != null) {
columnData.setTitle(attrTitle.getNodeValue());
}
Node attrAddon = node.getAttributes().getNamedItem("addon");
if (attrAddon != null) {
columnData.setAddon(attrAddon.getNodeValue());
} else {
columnData.setAddon("");
}
Node attrId = node.getAttributes().getNamedItem("id");
if (attrId != null) {
columnData.setId(attrId.getNodeValue());
}
result.add(columnData);
}
}
return result;
}
}

View File

@@ -0,0 +1,150 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-07-18
*/
package ru.dmitriymx.corrector1s.excel;
import lombok.Getter;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellReference;
import ru.dmitriymx.corrector1s.Utils;
import java.io.*;
public class ExcelDocument implements Closeable {
public static final int LINE_TITLE = 6,
LINE_ADDON = 7,
LINE_DATA = 8,
START_COLUMN = 7;
private Workbook workbook;
private Sheet sheet;
@Getter
private int maxLines;
/** последняя колонка в исходном документе */
@Getter
private int maxColumn;
public ExcelDocument(File excelFile) throws IOException, InvalidFormatException {
this.workbook = WorkbookFactory.create(excelFile);
this.sheet = this.workbook.getSheetAt(0);
// get max lines
for (int line = LINE_DATA; true; line++) {
if (this.sheet.getRow(line) == null) {
this.maxLines = line - 2;
break;
}
}
// get max column
for (int column = START_COLUMN; true; column++) {
if (this.sheet.getRow(LINE_ADDON).getCell(column) == null) {
this.maxColumn = column - 1;
break;
}
}
}
private String buildSumFormula(int column, int startLine, int endLine) {
String columnChar = CellReference.convertNumToColString(column);
return String.format("SUM(%s%d:%s%d)", columnChar, startLine + 1, columnChar, endLine + 1);
}
public ExcelRecordData getColumnRecord(int column) {
ExcelRecordData record = new ExcelRecordData(this.maxLines);
Cell cell;
for (int line = LINE_TITLE; line <= this.maxLines; line++) {
cell = this.sheet.getRow(line).getCell(column);
if (cell == null) break;
if (line == LINE_TITLE) {
record.setTitle(cell.getStringCellValue());
} else if (line == LINE_ADDON) {
if (cell.getCellTypeEnum().equals(CellType.NUMERIC)) {
record.setAddon(new Double(cell.getNumericCellValue()).intValue());
} else {
record.setAddon(0);
}
} else {
record.getDataList().add(cell.getNumericCellValue());
}
}
return record;
}
public void setColumnRecord(int column, ExcelRecord record) {
// TITLE
Cell cell = this.sheet.getRow(LINE_TITLE).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
cell.setCellType(CellType.STRING);
cell.setCellValue(record.getTitle());
// ADDON
cell = this.sheet.getRow(LINE_ADDON).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
if (record.isEmptyAddon()) {
cell.setCellType(CellType.BLANK);
}
// TODO мне очень не нравится такой подход. Нужно что-то более универсальное
else if (record instanceof ExcelRecordData){
cell.setCellType(CellType.NUMERIC);
cell.setCellValue((Integer)record.getAddon());
} else {
cell.setCellType(CellType.STRING);
cell.setCellValue((String)record.getAddon());
}
// DATA
for (int line = LINE_DATA; line <= this.maxLines; line++) {
cell = this.sheet.getRow(line).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
Object data = record.getDataList().get(line - LINE_DATA);
if (Utils.isEmptyObject(data)) {
cell.setCellType(CellType.BLANK);
}
// TODO мне очень не нравится такой подход. Нужно что-то более универсальное
else if (record instanceof ExcelRecordData) {
cell.setCellType(CellType.NUMERIC);
cell.setCellValue((Double) data);
} else {
cell.setCellType(CellType.FORMULA);
cell.setCellValue((String) data);
}
}
// SUM
cell = this.sheet.getRow(this.maxLines + 1).getCell(column, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
if (record.isEmptyData()) {
cell.setCellType(CellType.BLANK);
} else {
cell.setCellType(CellType.FORMULA);
cell.setCellFormula(buildSumFormula(column, LINE_DATA, this.maxLines));
}
}
public int getNumMergedCells() {
return this.sheet.getNumMergedRegions();
}
public CellRangeAddress getMergedCells(int id) {
return this.sheet.getMergedRegion(id);
}
public void removeMergedCells(int id) {
}
public void saveToFile(File file) throws IOException {
this.workbook.getCreationHelper().createFormulaEvaluator().evaluateAll();
try (FileOutputStream fos = new FileOutputStream(file)) {
this.workbook.write(fos);
}
}
@Override
public void close() throws IOException {
this.workbook.close();
}
}

View File

@@ -0,0 +1,20 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-07-18
*/
package ru.dmitriymx.corrector1s.excel;
import java.util.List;
public interface ExcelRecord<T1, T2> {
String getTitle();
void setTitle(String value);
T1 getAddon();
void setAddon(T1 value);
List<T2> getDataList();
boolean isEmptyAddon();
boolean isEmptyData();
}

View File

@@ -0,0 +1,36 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-07-18
*/
package ru.dmitriymx.corrector1s.excel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.util.ArrayList;
import java.util.List;
@Getter
@EqualsAndHashCode
public class ExcelRecordData implements ExcelRecord<Integer, Double> {
@Setter
private String title;
@Setter
private Integer addon;
private List<Double> dataList;
ExcelRecordData(int capacity) {
this.dataList = new ArrayList<>(capacity);
}
@Override
public boolean isEmptyAddon() {
return this.addon == 0;
}
@Override
public boolean isEmptyData() {
return this.dataList.stream().mapToDouble(Double::doubleValue).sum() == 0.0d;
}
}

View File

@@ -0,0 +1,37 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-07-18
*/
package ru.dmitriymx.corrector1s.excel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter
@EqualsAndHashCode
public class ExcelRecordFormula implements ExcelRecord<String, String> {
@Setter
private String title;
@Setter
private String addon;
private List<String> dataList;
@Override
public boolean isEmptyAddon() {
return this.addon == null || this.addon.trim().isEmpty();
}
@Override
public boolean isEmptyData() {
int i = 0;
for (String data : this.dataList) {
i += (data.trim().isEmpty() ? 1 : 0);
}
return i > 0;
}
}

View File

@@ -1,34 +0,0 @@
package ru.dmitriymx.corrector1s.gui;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import ru.dmitriymx.corrector1s.Main;
import java.io.IOException;
public class MainApp extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.setTitle(String.format("1С корректор (v%s)", Main.VERSION));
primaryStage.setResizable(false);
primaryStage.getIcons().add(new Image(getClass().getResourceAsStream("excel.png")));
primaryStage.setScene(loadScene(primaryStage));
primaryStage.show();
}
private Scene loadScene(Stage stage) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("single_layout.fxml"));
Scene scene = new Scene(loader.load(), 350-10, 203-10);
MainController controller = loader.getController();
controller.setStage(stage);
return scene;
}
}

View File

@@ -1,232 +0,0 @@
package ru.dmitriymx.corrector1s.gui;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.util.StringConverter;
import lombok.extern.slf4j.Slf4j;
import ru.dmitriymx.corrector1s.Corrector1S;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
@Slf4j
public class MainController {
private Stage stage;
@FXML
private TextField sourceFilePath;
@FXML
private TextField saveAsFilePath;
@FXML
private CheckBox saveAsCheckBox;
@FXML
private Button btnSourceFilePath;
@FXML
private Button btnSaveAsFilePath;
@FXML
private Pane mainPane;
@FXML
private Pane waitPane;
@FXML
private ProgressIndicator progressBar;
@FXML
private Button btnStartCorrect;
@FXML
private Spinner<Double> honorarium;
private SpinnerValueFactory<Double> honorariumValueFactory = new SpinnerValueFactory.DoubleSpinnerValueFactory(0.01d, 100.0d, 9.0d);
@FXML
private Spinner<Double> fss;
private SpinnerValueFactory<Double> fssValueFactory = new SpinnerValueFactory.DoubleSpinnerValueFactory(0.01d, 100.0d, 31.0d);
private FileChooser buildFileChooser(TextField textField) {
FileChooser fileChooser = new FileChooser();
if (!textField.getText().isEmpty() && Files.exists(Paths.get(textField.getText()))) {
File file = new File(textField.getText());
if (file.isDirectory()) {
fileChooser.setInitialDirectory(file);
} else {
fileChooser.setInitialDirectory(file.getParentFile());
}
}
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter(
"Таблицы Excel (*.xls, *.xlsx)",
"*.xls", "*.xlsx"));
return fileChooser;
}
private void enableInterface(boolean value) {
if (value) {
waitPane.setVisible(false);
mainPane.setOpacity(1.0d);
mainPane.setDisable(false);
} else {
mainPane.setDisable(true);
mainPane.setOpacity(0.3d);
waitPane.setVisible(true);
progressBar.setProgress(0d);
}
}
private Alert buildErrorDialog(String title, String text, Exception e) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle(title);
alert.setHeaderText(text);
VBox dialogPaneContent = new VBox();
Label label = new Label("Stack Trace:");
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
String stackTrace = sw.toString();
TextArea textArea = new TextArea();
textArea.setText(stackTrace);
dialogPaneContent.getChildren().addAll(label, textArea);
alert.getDialogPane().setContent(dialogPaneContent);
return alert;
}
private Alert buildInfoDialog(String title, String text) {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle(title);
alert.setHeaderText(null);
alert.setContentText(text);
return alert;
}
private <T> void commitEditorText(Spinner<T> spinner) {
if (!spinner.isEditable()) return;
String text = spinner.getEditor().getText();
SpinnerValueFactory<T> valueFactory = spinner.getValueFactory();
if (valueFactory != null) {
StringConverter<T> converter = valueFactory.getConverter();
if (converter != null) {
T value = converter.fromString(text);
valueFactory.setValue(value);
}
}
}
@FXML
public void initialize() {
honorarium.setValueFactory(honorariumValueFactory);
honorarium.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) return; // what?
commitEditorText(honorarium);
});
fss.setValueFactory(fssValueFactory);
fss.focusedProperty().addListener((observable, oldValue, newValue) -> {
if (newValue) return; // what?
commitEditorText(fss);
});
saveAsCheckBox.selectedProperty().addListener((observable, oldValue, newValue) -> {
saveAsFilePath.setDisable(!newValue);
btnSaveAsFilePath.setDisable(!newValue);
});
btnSourceFilePath.addEventHandler(ActionEvent.ACTION, event -> {
File file = buildFileChooser(sourceFilePath).showOpenDialog(stage);
if (file != null) {
sourceFilePath.setText(file.getAbsolutePath());
if (!saveAsCheckBox.selectedProperty().get()) {
saveAsFilePath.setText(file.getAbsolutePath());
}
}
});
btnSaveAsFilePath.addEventHandler(ActionEvent.ACTION, event -> {
File file = buildFileChooser(saveAsFilePath).showSaveDialog(stage);
if (file != null) {
saveAsFilePath.setText(file.getAbsolutePath());
}
});
btnStartCorrect.addEventHandler(ActionEvent.ACTION, event -> {
enableInterface(false);
Runnable runnable = () -> {
Corrector1S corrector = new Corrector1S();
corrector.setSourceFile(new File(sourceFilePath.getText()));
if (saveAsCheckBox.isSelected()) {
corrector.setTargetFile(new File(saveAsFilePath.getText()));
} else {
corrector.setTargetFile(new File(sourceFilePath.getText()));
}
log.info("Honorarium: {}", honorarium.getValue());
corrector.setHonorarium(honorarium.getValue());
log.info("FSS: {}", fss.getValue());
corrector.setFss(fss.getValue());
progressBar.setProgress(0.14d);
try {
corrector.check();
} catch (Exception e) {
log.error("Analize input data", e);
buildErrorDialog("Ошибка", "Ошибка при анализе входных данных", e)
.showAndWait();
enableInterface(true);
return;
}
progressBar.setProgress(0.28d);
try {
corrector.createSnapshotData();
} catch (Exception e) {
log.error("createSnapshotData", e);
buildErrorDialog("Ошибка", "Ошибка при обработке данных", e)
.showAndWait();
enableInterface(true);
return;
}
progressBar.setProgress(0.42d);
corrector.removeMergedCells();
progressBar.setProgress(0.56d);
corrector.replaceData();
progressBar.setProgress(0.70d);
corrector.insertNewCols();
corrector.insertNewLines();
progressBar.setProgress(0.99d);
try {
corrector.saveFile();
} catch (IOException e) {
log.error("saveFile", e);
buildErrorDialog("Ошибка", "Ошибка при сохранении файла", e)
.showAndWait();
enableInterface(true);
return;
}
progressBar.setProgress(1.0d);
buildInfoDialog("Информация", "Преобразование завершено успешно")
.showAndWait();
enableInterface(true);
};
Platform.runLater(runnable);
});
}
void setStage(Stage stage) {
this.stage = stage;
}
}

View File

@@ -0,0 +1,17 @@
/*
* DmitriyMX <dimon550@gmail.com>
* 2018-07-18
*/
package ru.dmitriymx.corrector1s;
import ru.dmitriymx.corrector1s.config.XmlConfig;
import java.io.InputStream;
public class Test {
public static void main(String[] args) throws Exception {
InputStream stream = Test.class.getResourceAsStream("/config.xml");
XmlConfig config = new XmlConfig(stream);
config.getColumnDataList().forEach(System.out::println);
}
}

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<config>
<columns>
<column title="Оклад" addon="101"/>
<column title="Отпуск очередной" addon="104"/>
<column title="Больничный за счет работодателя" addon="105"/>
<column title="Дневные"/>
<column title="Ночные"/>
<column title="Ночные" addon="123"/>
<column title="питание" addon="124"/>
<column title="Выходные"/>
<column title="выходные" addon="135"/>
<column title="пересчет за прошлый месяц" addon="141"/>
<column title="вредность" addon="145"/>
<column title="Материальная помощь при рождении ребенка" addon="148"/>
<column title="компенсация за задержку зарплаты" addon="169"/>
<column title="Оплата по среднему (донорство, посещение врача)" addon="174"/>
<column title="Компенсация проезда при использовании личного транспорта" addon="176"/>
<column title="сверхурочные" addon="133"/>
<column title="Сверхурочные 1.5 ставки"/>
<column title="сверхурочные 1,5" addon="180"/>
<column title="Сверхурочные 2 ставки"/>
<column title="сверхурочные 2" addon="181"/>
<column title="Компенсация за неиспользованный отпуск (с декабря 2017)" addon="184"/>
<column title="Месячная премия 2018" addon="186"/>
</columns>
<total_columns>
<column title="asdasdasd" formula="{1}*9%"/>
</total_columns>
<bottom_lines>
<line title="asdasdads" formula="{}+{}"/>
</bottom_lines>
</config>