From 5017f5f332a72067eb5b72d9a33bef13e4439432 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Mon, 23 May 2016 08:45:56 +0300 Subject: [PATCH] Init project --- .gitignore | 22 +++ pom.xml | 65 +++++++++ .../astralcheckreport/AstralSession.java | 68 +++++++++ .../astralcheckreport/ExcelDataRow.java | 27 ++++ .../astralcheckreport/ExcelReader.java | 42 ++++++ .../ru/dmitriymx/astralcheckreport/Main.java | 134 ++++++++++++++++++ .../astralcheckreport/objects/Product.java | 13 ++ .../astralcheckreport/objects/Tarif.java | 9 ++ .../objects/TarifDeserialize.java | 23 +++ .../ru/dmitriymx/tools/browser/Browser.java | 12 ++ .../tools/browser/SimpleBrowser.java | 131 +++++++++++++++++ src/main/resources/log4j2.xml | 13 ++ 12 files changed, 559 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/ru/dmitriymx/astralcheckreport/AstralSession.java create mode 100644 src/main/java/ru/dmitriymx/astralcheckreport/ExcelDataRow.java create mode 100644 src/main/java/ru/dmitriymx/astralcheckreport/ExcelReader.java create mode 100644 src/main/java/ru/dmitriymx/astralcheckreport/Main.java create mode 100644 src/main/java/ru/dmitriymx/astralcheckreport/objects/Product.java create mode 100644 src/main/java/ru/dmitriymx/astralcheckreport/objects/Tarif.java create mode 100644 src/main/java/ru/dmitriymx/astralcheckreport/objects/TarifDeserialize.java create mode 100644 src/main/java/ru/dmitriymx/tools/browser/Browser.java create mode 100644 src/main/java/ru/dmitriymx/tools/browser/SimpleBrowser.java create mode 100644 src/main/resources/log4j2.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d00fc37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +## IDEA ## +.idea/ +out/ +*.iml +*.ipr +*.iws +*.ids + +## ECLIPSE ## +.settings/ +bin/ +.classpath +.project + +## GRADLE ## +.gradle/ +build/ + +## OTHER ## +lib/ +target/ +config.ini diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..7771040 --- /dev/null +++ b/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + Astral check report + + + UTF-8 + 1.8 + 1.7.21 + 2.5 + + + ru.dmitriymx + astralcheckreport + jar + 1.0-SNAPSHOT + + + + org.slf4j + slf4j-api + ${slf4j-version} + + + org.apache.logging.log4j + log4j-slf4j-impl + ${log4j-version} + + + org.apache.logging.log4j + log4j-core + ${log4j-version} + + + com.google.code.gson + gson + 2.6.2 + + + org.apache.poi + poi-ooxml + 3.14 + + + + + ${artifactId}-${version} + + + org.apache.maven.plugins + maven-compiler-plugin + 3.5.1 + + ${java-version} + ${java-version} + UTF-8 + + + + + + diff --git a/src/main/java/ru/dmitriymx/astralcheckreport/AstralSession.java b/src/main/java/ru/dmitriymx/astralcheckreport/AstralSession.java new file mode 100644 index 0000000..e4b95d1 --- /dev/null +++ b/src/main/java/ru/dmitriymx/astralcheckreport/AstralSession.java @@ -0,0 +1,68 @@ +/* + * DmitriyMX + * 2016-05-19 + */ +package ru.dmitriymx.astralcheckreport; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import ru.dmitriymx.tools.browser.Browser; +import ru.dmitriymx.tools.browser.SimpleBrowser; + +public class AstralSession { + private Browser browser = new SimpleBrowser(); + private Gson gson = new Gson(); + + public AstralSession(String login, String password) { + String postData = + "ScriptManager1=UpdatePanel1%7CbtnLogin&" + + "__EVENTTARGET=&" + + "__EVENTARGUMENT=&" + + "__VIEWSTATE=%2FwEPDwUJNzM1ODg0MDkxZBgBBR5fX0NvbnRyb2xzUmVxdWlyZVBvc3RCYWNrS2V5X18WAQUPY2hlY2tSZW1lbWJlck1l9d9NT50uRqRp6BAIWN1qc0s9ySLBcPB%2BoxluO6cIJmA%3D&" + + "__EVENTVALIDATION=%2FwEdAAUilyZ6nKD9WwDOh8%2FNm7H8UxXZYJerTx8fFBZzRY0g5fGnUaknU6WWWdGPJ%2BD6CIXml3mJOTUsfp8Yps0tyqTvop4oRunf14dz2Zt2%2BQKDEDuvSfxPjsGW5RjhNO7o5Y2gKe5%2Fsvh5V%2BOOTpUxCP2F&" + + "tbxLogin=" + login + "&tbxPassword=" + password + "&" + + "__ASYNCPOST=true&" + + "btnLogin=%D0%92%D1%85%D0%BE%D0%B4"; + + browser.post("http://reg.astralnalog.ru/Authorisation.aspx", postData); + } + + public JsonObject findOrg(String inn, String kpp) { + String postData = "{\"context\":{\"CurrentPageIndex\":1,\"RecordsPerPage\":30," + + "\"AbonentName\":\"\",\"CompanyGroupName\":\"\"," + + "\"Inn\":\"" + inn + "\",\"Kpp\":\"" + kpp + "\"," + + "\"CreationDate\":\"\",\"ProductGuid\":\"\",\"RegNumPfr\":\"\",\"StepId\":\"0\"," + + "\"CreationInterval\":-1,\"SortingColumn\":\"abonentId\",\"SortingOrder\":\"desc\"}}"; + + browser.setHeader("Content-Type", "application/json;charset=utf-8"); + String jsonStr = browser.post("http://reg.astralnalog.ru/AbonentModule.aspx/GetAbonentData", postData); + + JsonObject jsonObj = str2jsonObj(jsonStr); + jsonObj = str2jsonObj(jsonObj.get("d").getAsString()); + int id = jsonObj.get("rows").getAsJsonArray().get(0).getAsJsonObject().get("id").getAsInt(); + + postData = "{\"abonentId\":\""+ id +"\"}"; + jsonStr = browser.post("http://reg.astralnalog.ru/AbonentModule.aspx/GetClientAbonentById", postData); + jsonObj = str2jsonObj(jsonStr); + jsonObj = str2jsonObj(jsonObj.get("d").getAsString()); + + return jsonObj; + } + + public JsonObject historyCert(int productId) { + String postData = "{\"productId\":" + productId + "}"; + String jsonStr = browser.post("http://reg.astralnalog.ru/AbonentModule.aspx/GetCertificatesHistory", postData); + + JsonObject jsonObj = str2jsonObj(jsonStr); + return str2jsonObj(jsonObj.get("d").getAsString()); + } + + private JsonObject str2jsonObj(String jsonStr) { + return gson.fromJson(jsonStr, JsonObject.class); + } + + @Override + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/ru/dmitriymx/astralcheckreport/ExcelDataRow.java b/src/main/java/ru/dmitriymx/astralcheckreport/ExcelDataRow.java new file mode 100644 index 0000000..2a6e532 --- /dev/null +++ b/src/main/java/ru/dmitriymx/astralcheckreport/ExcelDataRow.java @@ -0,0 +1,27 @@ +/* + * DmitriyMX + * 2016-05-20 + */ +package ru.dmitriymx.astralcheckreport; + +public class ExcelDataRow { + public String inn, kpp, tarif; + public int addonCert; + public int row; + + public ExcelDataRow(String inn, String kpp, String tarif, int addonCert, int row) { + this.inn = inn; + this.kpp = kpp; + this.tarif = tarif; + this.addonCert = addonCert; + this.row = row; + } + + @Override + public String toString() { + return "{inn: \"" + inn + + "\", kpp:\"" + kpp + + "\", tarif:\"" + tarif + + "\", addonCert:\"" + addonCert + "\"}"; + } +} diff --git a/src/main/java/ru/dmitriymx/astralcheckreport/ExcelReader.java b/src/main/java/ru/dmitriymx/astralcheckreport/ExcelReader.java new file mode 100644 index 0000000..6f5faca --- /dev/null +++ b/src/main/java/ru/dmitriymx/astralcheckreport/ExcelReader.java @@ -0,0 +1,42 @@ +/* + * DmitriyMX + * 2016-05-20 + */ +package ru.dmitriymx.astralcheckreport; + +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.usermodel.*; + +import java.io.File; +import java.io.IOException; + +public class ExcelReader { + private Workbook xls; + private Sheet sheet; + private int startRow = 10, + currentRow = startRow; + + public ExcelReader(File file, String sheetName) throws IOException, InvalidFormatException { + xls = WorkbookFactory.create(file); + sheet = xls.getSheet(sheetName); + } + + public ExcelDataRow getNextData() { + Row row = sheet.getRow(currentRow++); + Cell cellInn = row.getCell(2); + cellInn.setCellType(Cell.CELL_TYPE_STRING); + if (cellInn.getStringCellValue().isEmpty()) return null; + Cell cellKpp = row.getCell(3); + cellKpp.setCellType(Cell.CELL_TYPE_STRING); + Cell cellTarif = row.getCell(6); + Cell cellAddonCert = row.getCell(11); + cellAddonCert.setCellType(Cell.CELL_TYPE_NUMERIC); + + return new ExcelDataRow( + cellInn.getStringCellValue(), + cellKpp.getStringCellValue(), + cellTarif.getStringCellValue(), + (int)cellAddonCert.getNumericCellValue(), + currentRow); + } +} diff --git a/src/main/java/ru/dmitriymx/astralcheckreport/Main.java b/src/main/java/ru/dmitriymx/astralcheckreport/Main.java new file mode 100644 index 0000000..48c4d1a --- /dev/null +++ b/src/main/java/ru/dmitriymx/astralcheckreport/Main.java @@ -0,0 +1,134 @@ +/* + * DmitriyMX + * 2016-05-19 + */ +package ru.dmitriymx.astralcheckreport; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.reflect.TypeToken; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ru.dmitriymx.astralcheckreport.objects.Product; +import ru.dmitriymx.astralcheckreport.objects.Tarif; +import ru.dmitriymx.astralcheckreport.objects.TarifDeserialize; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Properties; + +public class Main implements Runnable { + private Logger logger = LoggerFactory.getLogger(Main.class); + private ExcelReader excel; + private Properties properties = new Properties(); + private Gson gson; + + public static void main(String[] args) { + new Main().start(); + } + + public Main() { + gson = new GsonBuilder() + .registerTypeAdapter(Tarif.class, new TarifDeserialize()) + .create(); + } + + public void start() { + logger.info("Astral check report v1.0"); + + logger.trace("Init config"); + try { + properties.load(new InputStreamReader(Main.class.getResourceAsStream("/config.ini"))); + } catch (IOException e) { + logger.error("Load config", e); + return; + } + + logger.trace("Load excel file"); + try { + excel = new ExcelReader(new File(properties.getProperty("file")), + properties.getProperty("sheet")); + } catch (IOException | InvalidFormatException e) { + logger.error("Load excel file", e); + return; + } + + ThreadGroup threadGroup = new ThreadGroup("Astral Clients"); + + for (int i = 0; i < 3; i++) { + Thread thread = new Thread(threadGroup, this, "ProcTH-"+(i+1)); + thread.start(); + safeSleep(200); + } + + while (threadGroup.activeCount() > 0) { + safeSleep(100); + } + + } + + public synchronized ExcelDataRow nextData() { + return excel.getNextData(); + } + + public static void safeSleep(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException ignore) { + // ignore + } + } + + @Override + public void run() { + logger.trace("Auth as \"{}\"...", properties.getProperty("login")); + AstralSession astral = new AstralSession( + properties.getProperty("login"), + properties.getProperty("password")); + + ExcelDataRow data; + while( !Thread.currentThread().isInterrupted() && ((data = nextData()) != null) ) { + if (!data.tarif.equalsIgnoreCase("Акция 3 месяца")) continue; //FIXME + logger.info("Check {} / {} ...", data.inn, data.kpp); + logger.debug("data = {}", data); + JsonObject jsonObj = astral.findOrg(data.inn, data.kpp); + logger.debug("result = {}", jsonObj.toString()); + + if (data.tarif.equalsIgnoreCase("Акция 3 месяца")) { + Product product = gson.fromJson(jsonObj.get("products").getAsJsonArray().get(0), Product.class); + Tarif tarif = product.contractTariffs.get(0); + + if (tarif.name.equalsIgnoreCase("Промо (3 месяца бесплатно)")) { + // 2016-03-25 + int mountInit = Integer.parseInt(tarif.initialDate.substring(5, 7)); + int mountEnd = Integer.parseInt(tarif.endDate.substring(5, 7)); + int delta = mountEnd - mountInit; + + if (delta != 3) { + logger.warn("({}/{}): tarif date error!", data.inn, data.kpp); + continue; + } + + JsonObject historyCert = astral.historyCert(product.id); + + int totalCert = historyCert.get("total").getAsInt(); + if (totalCert > 1) { + if (totalCert != (1 + data.addonCert)) { + logger.warn("({}/{}): error history cert", data.inn, data.kpp); + continue; + } + } + } else if (tarif.name.equalsIgnoreCase("Cтандартный (годовое обслуживание)")) { + logger.info("No logic tarif: \"{}\"", tarif.name); + } else { + logger.trace("Ignore tarif: \"{}\"", tarif.name); + } + } + + safeSleep(200); + } + } +} diff --git a/src/main/java/ru/dmitriymx/astralcheckreport/objects/Product.java b/src/main/java/ru/dmitriymx/astralcheckreport/objects/Product.java new file mode 100644 index 0000000..12dfcfe --- /dev/null +++ b/src/main/java/ru/dmitriymx/astralcheckreport/objects/Product.java @@ -0,0 +1,13 @@ +/* + * DmitriyMX + * 2016-05-21 + */ +package ru.dmitriymx.astralcheckreport.objects; + +import java.util.List; + +public class Product { + public int id; + public String name; + public List contractTariffs; +} diff --git a/src/main/java/ru/dmitriymx/astralcheckreport/objects/Tarif.java b/src/main/java/ru/dmitriymx/astralcheckreport/objects/Tarif.java new file mode 100644 index 0000000..70c11ee --- /dev/null +++ b/src/main/java/ru/dmitriymx/astralcheckreport/objects/Tarif.java @@ -0,0 +1,9 @@ +/* + * DmitriyMX + * 2016-05-21 + */ +package ru.dmitriymx.astralcheckreport.objects; + +public class Tarif { + public String name, initialDate, endDate; +} diff --git a/src/main/java/ru/dmitriymx/astralcheckreport/objects/TarifDeserialize.java b/src/main/java/ru/dmitriymx/astralcheckreport/objects/TarifDeserialize.java new file mode 100644 index 0000000..f7e5933 --- /dev/null +++ b/src/main/java/ru/dmitriymx/astralcheckreport/objects/TarifDeserialize.java @@ -0,0 +1,23 @@ +/* + * DmitriyMX + * 2016-05-21 + */ +package ru.dmitriymx.astralcheckreport.objects; + +import com.google.gson.*; + +import java.lang.reflect.Type; + +public class TarifDeserialize implements JsonDeserializer { + @Override + public Tarif deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { + Tarif tarif = new Tarif(); + JsonObject jsonObject = jsonElement.getAsJsonObject(); + + tarif.name = jsonObject.get("tariff").getAsJsonObject().get("name").getAsString(); + tarif.initialDate = jsonObject.get("initialDate").getAsString(); + tarif.endDate = jsonObject.get("endDate").getAsString(); + + return tarif; + } +} diff --git a/src/main/java/ru/dmitriymx/tools/browser/Browser.java b/src/main/java/ru/dmitriymx/tools/browser/Browser.java new file mode 100644 index 0000000..491ed86 --- /dev/null +++ b/src/main/java/ru/dmitriymx/tools/browser/Browser.java @@ -0,0 +1,12 @@ +/* + * DmitriyMX + * 2016-04-12 + */ +package ru.dmitriymx.tools.browser; + +public interface Browser { + void setEncoding(String encoding); + Browser setHeader(String name, String value); + String get(String url); + String post(String url, String data); +} diff --git a/src/main/java/ru/dmitriymx/tools/browser/SimpleBrowser.java b/src/main/java/ru/dmitriymx/tools/browser/SimpleBrowser.java new file mode 100644 index 0000000..2a89b74 --- /dev/null +++ b/src/main/java/ru/dmitriymx/tools/browser/SimpleBrowser.java @@ -0,0 +1,131 @@ +/* + * DmitriyMX + * 2016-04-12 + */ +package ru.dmitriymx.tools.browser; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringJoiner; + +public class SimpleBrowser implements Browser { + private Map headers = new HashMap<>(); + private String encoding = "UTF-8"; + private Map cookieStore = new HashMap<>(); + private String cookieStoreCache = null; + + @Override + public void setEncoding(String encoding) { + if (encoding != null) this.encoding = encoding; + } + + @Override + public Browser setHeader(String name, String value) { + headers.put(name, value); + return this; + } + + @Override + public String get(String url) { + String result = ""; + try { + HttpURLConnection connection = create_connection(url); + connection.setRequestMethod("GET"); + + if (connection.getResponseCode() != 200) return ""; + + saveCookie(connection.getHeaderFields()); + + result = readOutput(connection.getInputStream()); + connection.disconnect(); + } catch (IOException ignore) { //TODO прикрутить логгер + // ignore + } + return result; + } + + @Override + public String post(String url, String data) { + String result = ""; + try { + HttpURLConnection connection = create_connection(url); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Length", String.valueOf(data.length())); + + connection.setDoOutput(true); + DataOutputStream dos = new DataOutputStream(connection.getOutputStream()); + dos.writeBytes(data); + dos.flush(); + dos.close(); + + if (connection.getResponseCode() != 200) return ""; + + saveCookie(connection.getHeaderFields()); + + result = readOutput(connection.getInputStream()); + connection.disconnect(); + } catch (IOException ignore) { //TODO прикрутить логгер + // ignore + } + return result; + } + + private HttpURLConnection create_connection(String strUrl) throws IOException { + URL url = new URL(strUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + + connection.setUseCaches(false); //TODO а надо ли? + + connection.setRequestProperty("Connection", "close"); + connection.setRequestProperty("Accept-Encoding", "deflate"); + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 4.2.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36"); + connection.setRequestProperty("Cookie", loadCookie()); + + for (Map.Entry entry : headers.entrySet()) { + connection.setRequestProperty(entry.getKey(), entry.getValue()); + } + + return connection; + } + + private String readOutput(InputStream in) throws IOException { + StringJoiner stringJoiner = new StringJoiner("\n"); + BufferedReader br = new BufferedReader(new InputStreamReader(in, encoding)); + String line; + while ((line = br.readLine()) != null) { + stringJoiner.add(line); + } + br.close(); + + return stringJoiner.toString(); + } + + private void saveCookie(Map> headers) { + if (headers.containsKey("Set-Cookie")) { + cookieStoreCache = null; + for (String cookieLine : headers.get("Set-Cookie")) { + String cookiePair = cookieLine.split(";", 2)[0]; + String[] keyValue = cookiePair.split("="); + cookieStore.put(keyValue[0], keyValue[1]); + } + } + } + + private String loadCookie() { + if (cookieStoreCache == null) { + if (cookieStore.isEmpty()) { + cookieStoreCache = ""; + } + StringJoiner sj = new StringJoiner(";"); + for (String key : cookieStore.keySet()) { + sj.add(key + "=" + cookieStore.get(key)); + } + cookieStoreCache = sj.toString(); + } + return cookieStoreCache; + } +} diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..dc9db79 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file