Refactor and enhance transaction handling and logging
Introduced new logging system with QInstallMessageHandler. Refactored NetworkService for better modularity and added new methods to handle transaction data. Updated database schema and TransactionDAO to support external transaction ID. Cleaned up and streamlined transaction processing in GetLastDaysHistoryScript.
This commit is contained in:
parent
edcd931e66
commit
a506bca01d
@ -1,8 +1,12 @@
|
||||
#include "CommonScript.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QRandomGenerator>
|
||||
#include <QThread>
|
||||
|
||||
#include "adb/AdbUtils.h"
|
||||
#include "net/NetworkService.h"
|
||||
|
||||
CommonScript::CommonScript(QObject *parent)
|
||||
: QObject(parent) {
|
||||
@ -205,6 +209,95 @@ bool CommonScript::findAndTapOnAccount(const QString &deviceId, const QString &a
|
||||
}
|
||||
|
||||
|
||||
void CommonScript::postAccountsData(const QList<QPair<AccountInfo, Node> > &accounts) {
|
||||
if (accounts.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *thread = new QThread;
|
||||
auto *worker = new NetworkService;
|
||||
|
||||
QJsonArray list;
|
||||
for (const QPair<AccountInfo, Node> &pair: accounts) {
|
||||
QJsonObject obj;
|
||||
AccountInfo account = pair.first;
|
||||
obj["appName"] = account.appName;
|
||||
obj["lastNumbers"] = account.lastNumbers;
|
||||
obj["amount"] = account.amount;
|
||||
obj["description"] = account.description;
|
||||
|
||||
list.append(obj);
|
||||
}
|
||||
// FIXME доставить десктоп ид из настроеек
|
||||
worker->setDeviceData("DT88bokcwQ", accounts.first().first.deviceId);
|
||||
worker->setPayload(QJsonDocument(list).toJson());
|
||||
worker->moveToThread(thread);
|
||||
connect(thread, &QThread::started, worker, &NetworkService::postAccountsData);
|
||||
connect(worker, &NetworkService::finished, thread, &QThread::quit);
|
||||
connect(worker, &NetworkService::finished, worker, &QObject::deleteLater);
|
||||
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void CommonScript::postNewTransactionData(const AccountInfo &account, const TransactionInfo &transaction) {
|
||||
auto *thread = new QThread;
|
||||
auto *worker = new NetworkService;
|
||||
|
||||
QJsonObject obj;
|
||||
obj["id"] = transaction.id;
|
||||
obj["amount"] = transaction.amount;
|
||||
obj["name"] = transaction.name;
|
||||
obj["fee"] = transaction.fee;
|
||||
obj["status"] = transactionStatusToString(transaction.status);
|
||||
obj["type"] = transactionTypeToString(transaction.type);
|
||||
obj["phone"] = transaction.phone;
|
||||
obj["description"] = transaction.description;
|
||||
obj["updatedDescription"] = transaction.updatedDescription;
|
||||
obj["bankName"] = transaction.bankName;
|
||||
obj["bankTime"] = transaction.bankTime;
|
||||
obj["bankTransactionId"] = transaction.bankTrExternalId;
|
||||
|
||||
// FIXME доставить десктоп ид из настроеек
|
||||
worker->setDeviceData("DT88bokcwQ", account.deviceId);
|
||||
worker->addExtra("lastNumbers", account.lastNumbers);
|
||||
worker->addExtra("transactionId", transaction.id);
|
||||
worker->setPayload(QJsonDocument(obj).toJson());
|
||||
worker->moveToThread(thread);
|
||||
connect(thread, &QThread::started, worker, &NetworkService::insertTransactionData);
|
||||
connect(worker, &NetworkService::finished, thread, &QThread::quit);
|
||||
connect(worker, &NetworkService::finished, worker, &QObject::deleteLater);
|
||||
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void CommonScript::updateTransactionData(
|
||||
const AccountInfo &account,
|
||||
const int transactionId,
|
||||
const TransactionStatus status,
|
||||
const QString &oldDesc,
|
||||
const QString &newDesc
|
||||
) {
|
||||
auto *thread = new QThread;
|
||||
auto *worker = new NetworkService;
|
||||
|
||||
QJsonObject obj;
|
||||
obj["id"] = transactionId;
|
||||
obj["status"] = transactionStatusToString(status);
|
||||
obj["description"] = newDesc;
|
||||
obj["updatedDescription"] = oldDesc;
|
||||
|
||||
// FIXME доставить десктоп ид из настроеек
|
||||
worker->setDeviceData("DT88bokcwQ", account.deviceId);
|
||||
worker->addExtra("lastNumbers", account.lastNumbers);
|
||||
worker->setPayload(QJsonDocument(obj).toJson());
|
||||
worker->moveToThread(thread);
|
||||
connect(thread, &QThread::started, worker, &NetworkService::updateTransactionData);
|
||||
connect(worker, &NetworkService::finished, thread, &QThread::quit);
|
||||
connect(worker, &NetworkService::finished, worker, &QObject::deleteLater);
|
||||
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void CommonScript::stop() {
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
@ -25,6 +25,18 @@ protected:
|
||||
|
||||
bool findAndTapOnAccount(const QString &deviceId, const QString &accountNumbers);
|
||||
|
||||
void postAccountsData(const QList<QPair<AccountInfo, Node> > &accounts);
|
||||
|
||||
void postNewTransactionData(const AccountInfo &account, const TransactionInfo &transaction);
|
||||
|
||||
void updateTransactionData(
|
||||
const AccountInfo &account,
|
||||
int transactionId,
|
||||
TransactionStatus status,
|
||||
const QString &oldDesc,
|
||||
const QString &newDesc
|
||||
);
|
||||
|
||||
Node swipeToButton(
|
||||
const QString &deviceId,
|
||||
const QString &text,
|
||||
@ -49,6 +61,7 @@ protected:
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
void finishedWithResult(const QString &result);
|
||||
|
||||
public slots:
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#include "GetLastDaysHistoryScript.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QRandomGenerator>
|
||||
#include <QThread>
|
||||
@ -84,89 +83,104 @@ QString formatPrice(const double value) {
|
||||
return QString("%1 %2").arg(sign, formatted);
|
||||
}
|
||||
|
||||
bool GetLastDaysHistoryScript::openAndSaveDitailInfo(TransactionInfo &transaction, int width, int height) {
|
||||
QString text = QString("%1 %2").arg(transaction.shortDescription, formatPrice(transaction.amount));
|
||||
// bool GetLastDaysHistoryScript::openAndSaveDitailInfo(TransactionInfo &transaction, int width, int height) {
|
||||
// QString text = QString("%1 %2").arg(transaction.shortDescription, formatPrice(transaction.amount));
|
||||
//
|
||||
// Node trButton = swipeToButton(m_account.deviceId, text, m_counter, width, height);
|
||||
// if (!trButton.isEmpty()) {
|
||||
// AdbUtils::makeTap(m_account.deviceId, trButton.x(), trButton.y());
|
||||
// QThread::msleep(500);
|
||||
//
|
||||
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
|
||||
//
|
||||
// Node moreDetailBtn = xmlScreenParser.findButtonNode("Детали операции", false);
|
||||
// if (!moreDetailBtn.isEmpty()) {
|
||||
// AdbUtils::makeTap(m_account.deviceId, moreDetailBtn.x(), moreDetailBtn.y());
|
||||
// QThread::msleep(200);
|
||||
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
|
||||
// TransactionInfo info = xmlScreenParser.parseTransactionInfoHistory(width, height);
|
||||
//
|
||||
// if (transaction.id == -1) {
|
||||
// info.accountId = m_account.id;
|
||||
// info.shortDescription = transaction.shortDescription;
|
||||
// info.amount = transaction.amount;
|
||||
// info.type = info.phone.isEmpty() ? TransactionType::Card : TransactionType::Phone;
|
||||
// info.updateTime = DateUtils::getUtcNow();
|
||||
// if (info.status == TransactionStatus::Complete) {
|
||||
// info.completeTime = DateUtils::getUtcNow();
|
||||
// }
|
||||
// if (TransactionDAO::insertTransaction(info) == -1) {
|
||||
// qWarning() << "--- insertTransaction failed";
|
||||
// }
|
||||
// } else {
|
||||
// transaction.status = info.status;
|
||||
// transaction.description = info.description;
|
||||
// if (transaction.trExternalId.isEmpty()) {
|
||||
// transaction.trExternalId = info.trExternalId;
|
||||
// }
|
||||
// transaction.updateTime = DateUtils::getUtcNow();
|
||||
// if (transaction.status == TransactionStatus::Complete && !transaction.completeTime.isValid()) {
|
||||
// transaction.completeTime = DateUtils::getUtcNow();
|
||||
// }
|
||||
// if (!TransactionDAO::updateTransaction(transaction)) {
|
||||
// qWarning() << "--- updateTransaction failed";
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// AdbUtils::goBack(m_account.deviceId);
|
||||
// QThread::msleep(200);
|
||||
// } else {
|
||||
// qWarning() << "--- trButton not found..........";
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
Node trButton = swipeToButton(m_account.deviceId, text, m_counter, width, height);
|
||||
if (!trButton.isEmpty()) {
|
||||
AdbUtils::makeTap(m_account.deviceId, trButton.x(), trButton.y());
|
||||
QThread::msleep(500);
|
||||
bool GetLastDaysHistoryScript::saveAndPostNewTransactionData(
|
||||
const AccountInfo &account,
|
||||
const TransactionInfo &transaction
|
||||
) {
|
||||
TransactionInfo tr;
|
||||
tr.accountId = account.id;
|
||||
tr.description = transaction.description;
|
||||
tr.bankTime = transaction.bankTime;
|
||||
tr.bankName = transaction.bankName;
|
||||
tr.amount = transaction.amount;
|
||||
tr.phone = transaction.phone;
|
||||
tr.updateTime = DateUtils::getUtcNow();
|
||||
tr.fee = transaction.fee;
|
||||
tr.name = transaction.name;
|
||||
tr.bankTrExternalId = transaction.bankTrExternalId;
|
||||
tr.status = TransactionStatus::Complete;
|
||||
tr.type = transaction.description.startsWith("Перевод") ? TransactionType::Phone : TransactionType::Card;
|
||||
tr.completeTime = DateUtils::getUtcNow();
|
||||
tr.id = TransactionDAO::insertTransaction(tr);
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
|
||||
if (tr.id == -1) {
|
||||
return false;
|
||||
}
|
||||
postNewTransactionData(account, tr);
|
||||
return true;
|
||||
}
|
||||
|
||||
Node moreDetailBtn = xmlScreenParser.findButtonNode("Детали операции", false);
|
||||
if (!moreDetailBtn.isEmpty()) {
|
||||
AdbUtils::makeTap(m_account.deviceId, moreDetailBtn.x(), moreDetailBtn.y());
|
||||
QThread::msleep(200);
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
|
||||
TransactionInfo info = xmlScreenParser.parseTransactionInfoHistory(width, height);
|
||||
|
||||
if (transaction.id == -1) {
|
||||
info.accountId = m_account.id;
|
||||
info.shortDescription = transaction.shortDescription;
|
||||
info.amount = transaction.amount;
|
||||
info.type = info.phone.isEmpty() ? TransactionType::Card : TransactionType::Phone;
|
||||
info.updateTime = DateUtils::getUtcNow();
|
||||
if (info.status == TransactionStatus::Complete) {
|
||||
info.completeTime = DateUtils::getUtcNow();
|
||||
}
|
||||
if (TransactionDAO::insertTransaction(info) == -1) {
|
||||
qWarning() << "--- insertTransaction failed";
|
||||
}
|
||||
} else {
|
||||
transaction.status = info.status;
|
||||
transaction.description = info.description;
|
||||
if (transaction.trExternalId.isEmpty()) {
|
||||
transaction.trExternalId = info.trExternalId;
|
||||
}
|
||||
transaction.updateTime = DateUtils::getUtcNow();
|
||||
if (transaction.status == TransactionStatus::Complete && !transaction.completeTime.isValid()) {
|
||||
transaction.completeTime = DateUtils::getUtcNow();
|
||||
}
|
||||
if (!TransactionDAO::updateTransaction(transaction)) {
|
||||
qWarning() << "--- updateTransaction failed";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AdbUtils::goBack(m_account.deviceId);
|
||||
QThread::msleep(200);
|
||||
} else {
|
||||
qWarning() << "--- trButton not found..........";
|
||||
bool GetLastDaysHistoryScript::updateAndPostTransactionData(
|
||||
const AccountInfo &account,
|
||||
const int transactionId,
|
||||
const TransactionStatus status,
|
||||
const QString &oldDesc,
|
||||
const QString &newDesc
|
||||
) {
|
||||
if (TransactionDAO::updateTransaction(transactionId, status, oldDesc, newDesc)) {
|
||||
updateTransactionData(account, transactionId, status, oldDesc, newDesc);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void postAccountsData(const QList<QPair<AccountInfo, Node> > &accounts) {
|
||||
if (accounts.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *thread = new QThread;
|
||||
auto *worker = new NetworkService;
|
||||
|
||||
QJsonArray list;
|
||||
for (const QPair<AccountInfo, Node> &pair: accounts) {
|
||||
QJsonObject obj;
|
||||
AccountInfo account = pair.first;
|
||||
obj["appName"] = account.appName;
|
||||
obj["lastNumbers"] = account.lastNumbers;
|
||||
obj["amount"] = account.amount;
|
||||
obj["description"] = account.description;
|
||||
|
||||
list.append(obj);
|
||||
}
|
||||
worker->setDeviceData("DT88bokcwQ", accounts.first().first.deviceId);
|
||||
worker->setPayload(QJsonDocument(list).toJson());
|
||||
worker->moveToThread(thread);
|
||||
QObject::connect(thread, &QThread::started, worker, &NetworkService::postAccountsData);
|
||||
QObject::connect(worker, &NetworkService::finished, thread, &QThread::quit);
|
||||
QObject::connect(worker, &NetworkService::finished, worker, &QObject::deleteLater);
|
||||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||
thread->start();
|
||||
}
|
||||
|
||||
void GetLastDaysHistoryScript::doStart() {
|
||||
|
||||
return;
|
||||
|
||||
// берем все транзакции из БД
|
||||
QList<TransactionInfo> localTransactions = TransactionDAO::getTransactionsWithinHours(m_account.id, 48);
|
||||
const DeviceInfo device = DeviceDAO::getDeviceById(m_account.deviceId);
|
||||
@ -230,8 +244,6 @@ void GetLastDaysHistoryScript::doStart() {
|
||||
// все поддвержденные
|
||||
QList<TransactionInfo> parsedTransactions = xmlScreenParser.parseTodayAndYesterdayReportHistory();
|
||||
QSet<int> parsedTransactionIds;
|
||||
qDebug() << "--- parsedTransactions: " << parsedTransactions.length();
|
||||
qDebug() << "--- localTransactions: " << localTransactions.length();
|
||||
for (const TransactionInfo &transaction: parsedTransactions) {
|
||||
bool updated = false;
|
||||
|
||||
@ -353,25 +365,8 @@ void GetLastDaysHistoryScript::doStart() {
|
||||
}
|
||||
if (!updated) {
|
||||
qDebug() << "--- insert: " << transaction.description;
|
||||
// не нашлась транзакция
|
||||
TransactionInfo tr;
|
||||
tr.accountId = m_account.id;
|
||||
tr.description = transaction.description;
|
||||
tr.bankTime = transaction.bankTime;
|
||||
tr.bankName = transaction.bankName;
|
||||
tr.amount = transaction.amount;
|
||||
tr.phone = transaction.phone;
|
||||
tr.updateTime = DateUtils::getUtcNow();
|
||||
tr.fee = transaction.fee;
|
||||
tr.name = transaction.name;
|
||||
tr.trExternalId = transaction.trExternalId;
|
||||
tr.status = TransactionStatus::Complete;
|
||||
tr.type = transaction.description.startsWith("Перевод")
|
||||
? TransactionType::Phone
|
||||
: TransactionType::Card;
|
||||
tr.completeTime = DateUtils::getUtcNow();
|
||||
if (TransactionDAO::insertTransaction(tr) == -1) {
|
||||
qDebug() << "--- not inserted: " << transaction.description;
|
||||
if (!saveAndPostNewTransactionData(m_account, transaction)) {
|
||||
qDebug() << "--- saveAndPostNewTransactionData failed";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -18,5 +18,13 @@ protected:
|
||||
private:
|
||||
const AccountInfo m_account;
|
||||
|
||||
bool openAndSaveDitailInfo(TransactionInfo &transaction, int width, int height);
|
||||
bool saveAndPostNewTransactionData(const AccountInfo &account, const TransactionInfo &transaction);
|
||||
|
||||
bool updateAndPostTransactionData(
|
||||
const AccountInfo &account,
|
||||
int transactionId,
|
||||
TransactionStatus status,
|
||||
const QString &oldDesc,
|
||||
const QString &newDesc
|
||||
);
|
||||
};
|
||||
|
||||
@ -244,6 +244,13 @@ void PayByPhoneScript::doStart() {
|
||||
const DeviceInfo device = DeviceDAO::getDeviceById(m_account.deviceId);
|
||||
const ApplicationInfo app = ApplicationDAO::getApplicationsByDeviceId(m_account.deviceId, m_account.appName);
|
||||
|
||||
for (TransactionInfo &transaction: TransactionDAO::getTransactions(m_account.id)) {
|
||||
// postNewTransactionData(m_account, transaction);
|
||||
updateTransactionData(m_account, transaction.id, transaction.status, transaction.updatedDescription, transaction.description);
|
||||
}
|
||||
|
||||
emit finishedWithResult(m_error);
|
||||
return;
|
||||
if (device.id.isEmpty() || app.id.isEmpty()) {
|
||||
qDebug() << "Device or app not found....";
|
||||
return;
|
||||
|
||||
@ -339,9 +339,9 @@ void parseTransferInfo(const QString &text, TransactionInfo &info) {
|
||||
}
|
||||
|
||||
if (const auto m = reSbpId.match(text); m.hasMatch()) {
|
||||
info.trExternalId = m.captured(1);
|
||||
info.bankTrExternalId = m.captured(1);
|
||||
} else if (const auto m1 = reIdAlt.match(text); m1.hasMatch()) {
|
||||
info.trExternalId = m1.captured(1);
|
||||
info.bankTrExternalId = m1.captured(1);
|
||||
}
|
||||
|
||||
if (const auto m = reDate.match(text); m.hasMatch()) {
|
||||
@ -864,7 +864,7 @@ TransactionInfo parseExpandedInfo(const QDomElement &root) {
|
||||
break;
|
||||
case 10:
|
||||
ee = findSubElement(infoElement, "1");
|
||||
transaction.trExternalId = findSubInfo(ee, "1");
|
||||
transaction.bankTrExternalId = findSubInfo(ee, "1");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
Binary file not shown.
@ -41,12 +41,12 @@ bool TransactionDAO::insertTransactionIfNotExists(const TransactionInfo &info) {
|
||||
INSERT INTO transactions (
|
||||
account_id, amount, fee, status, phone, type,
|
||||
description, updated_description, short_description, updated_short_description,
|
||||
bank_name, bank_time, name, tr_external_id,
|
||||
bank_name, bank_time, name, bank_tr_external_id,
|
||||
update_time, complete_time, timestamp
|
||||
) VALUES (
|
||||
:account_id, :amount, :fee, :status, :phone, :type,
|
||||
:description, :updated_description, :short_description, :updated_short_description,
|
||||
:bank_name, :bank_time, :name, :tr_external_id,
|
||||
:bank_name, :bank_time, :name, :bank_tr_external_id,
|
||||
:update_time, :complete_time, :timestamp
|
||||
)
|
||||
)");
|
||||
@ -64,7 +64,7 @@ bool TransactionDAO::insertTransactionIfNotExists(const TransactionInfo &info) {
|
||||
query.bindValue(":updated_short_description", info.updatedShortDescription);
|
||||
query.bindValue(":bank_name", info.bankName);
|
||||
query.bindValue(":bank_time", info.bankTime);
|
||||
query.bindValue(":tr_external_id", info.trExternalId);
|
||||
query.bindValue(":bank_tr_external_id", info.bankTrExternalId);
|
||||
query.bindValue(":update_time", DateUtils::toUtcString(info.updateTime));
|
||||
query.bindValue(":complete_time", DateUtils::toUtcString(info.completeTime));
|
||||
|
||||
@ -83,12 +83,12 @@ int TransactionDAO::insertTransaction(const TransactionInfo &info) {
|
||||
INSERT INTO transactions (
|
||||
account_id, amount, fee, status, phone, type,
|
||||
description, updated_description, short_description, updated_short_description,
|
||||
bank_name, bank_time, name, tr_external_id,
|
||||
bank_name, bank_time, name, bank_tr_external_id,
|
||||
update_time, complete_time
|
||||
) VALUES (
|
||||
:account_id, :amount, :fee, :status, :phone, :type,
|
||||
:description, :updated_description, :short_description, :updated_short_description,
|
||||
:bank_name, :bank_time, :name, :tr_external_id,
|
||||
:bank_name, :bank_time, :name, :bank_tr_external_id,
|
||||
:update_time, :complete_time
|
||||
)
|
||||
)");
|
||||
@ -106,7 +106,7 @@ int TransactionDAO::insertTransaction(const TransactionInfo &info) {
|
||||
query.bindValue(":updated_short_description", info.updatedShortDescription);
|
||||
query.bindValue(":bank_name", info.bankName);
|
||||
query.bindValue(":bank_time", info.bankTime);
|
||||
query.bindValue(":tr_external_id", info.trExternalId);
|
||||
query.bindValue(":bank_tr_external_id", info.bankTrExternalId);
|
||||
query.bindValue(":update_time", DateUtils::toUtcString(info.updateTime));
|
||||
query.bindValue(":complete_time", DateUtils::toUtcString(info.completeTime));
|
||||
|
||||
@ -142,7 +142,7 @@ TransactionInfo parseTransaction(const QSqlQuery &query) {
|
||||
tx.updatedShortDescription = query.value("updated_short_description").toString();
|
||||
tx.bankName = query.value("bank_name").toString();
|
||||
tx.bankTime = query.value("bank_time").toString();
|
||||
tx.trExternalId = query.value("tr_external_id").toString();
|
||||
tx.bankTrExternalId = query.value("bank_tr_external_id").toString();
|
||||
tx.updateTime = DateUtils::fromUtcString(query.value("update_time").toString());
|
||||
tx.completeTime = DateUtils::fromUtcString(query.value("complete_time").toString());
|
||||
tx.timestamp = DateUtils::fromUtcString(query.value("timestamp").toString());
|
||||
@ -193,7 +193,7 @@ bool TransactionDAO::updateTransaction(const TransactionInfo &info) {
|
||||
bank_name = :bank_name,
|
||||
bank_time = :bank_time,
|
||||
name = :name,
|
||||
tr_external_id = :tr_external_id,
|
||||
bank_tr_external_id = :bank_tr_external_id,
|
||||
update_time = :update_time,
|
||||
complete_time = :complete_time,
|
||||
timestamp = :timestamp
|
||||
@ -213,7 +213,7 @@ bool TransactionDAO::updateTransaction(const TransactionInfo &info) {
|
||||
query.bindValue(":updated_short_description", info.updatedShortDescription);
|
||||
query.bindValue(":bank_name", info.bankName);
|
||||
query.bindValue(":bank_time", info.bankTime);
|
||||
query.bindValue(":tr_external_id", info.trExternalId);
|
||||
query.bindValue(":bank_tr_external_id", info.bankTrExternalId);
|
||||
query.bindValue(":update_time", DateUtils::toUtcString(info.updateTime));
|
||||
query.bindValue(":complete_time", DateUtils::toUtcString(info.completeTime));
|
||||
query.bindValue(":timestamp", DateUtils::toUtcString(info.timestamp));
|
||||
@ -335,3 +335,22 @@ bool TransactionDAO::updateTransaction(
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransactionDAO::updateExternalTransactionId(const int id, const int externalId) {
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
|
||||
query.prepare(R"(
|
||||
UPDATE transactions SET
|
||||
external_id = :external_id
|
||||
WHERE id = :id
|
||||
)");
|
||||
|
||||
query.bindValue(":id", id);
|
||||
query.bindValue(":external_id", externalId);
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Ошибка при обновлении external_id:" << query.lastError().text();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -25,4 +25,6 @@ public:
|
||||
const QString &oldDesc,
|
||||
const QString &newDesc
|
||||
);
|
||||
|
||||
[[nodiscard]] static bool updateExternalTransactionId(int id, int externalId);
|
||||
};
|
||||
|
||||
95
main.cpp
95
main.cpp
@ -14,6 +14,7 @@
|
||||
#include <cstdlib>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <QFile>
|
||||
|
||||
#include "rshb/GetLastDaysHistoryScript.h"
|
||||
#include "rshb/HomeScreenScript.h"
|
||||
@ -59,7 +60,8 @@ void setupWorkerAndThreadHistory(QCoreApplication &app) {
|
||||
deviceScreenerWorker->moveToThread(thread);
|
||||
QObject::connect(thread, &QThread::started, deviceScreenerWorker, &GetLastDaysHistoryScript::start);
|
||||
QObject::connect(deviceScreenerWorker, &GetLastDaysHistoryScript::finished, thread, &QThread::quit);
|
||||
QObject::connect(deviceScreenerWorker, &GetLastDaysHistoryScript::finished, deviceScreenerWorker, &QObject::deleteLater);
|
||||
QObject::connect(deviceScreenerWorker, &GetLastDaysHistoryScript::finished, deviceScreenerWorker,
|
||||
&QObject::deleteLater);
|
||||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||
QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() {
|
||||
deviceScreenerWorker->stop();
|
||||
@ -75,7 +77,7 @@ void setupScriptAutoPaymentAndThread(QCoreApplication &app) {
|
||||
const QString phoneNumber = "79641815146";
|
||||
const QString bankName = "Альфа-Банк";
|
||||
// const QString bankName = "Сбербанк";
|
||||
const double amount = 520;
|
||||
const double amount = 320;
|
||||
|
||||
const AccountInfo account = AccountDAO::findAppAccount(appName, cardNumber);
|
||||
if (account.id != -1) {
|
||||
@ -104,25 +106,29 @@ void setupScriptAutoPaymentAndThread(QCoreApplication &app) {
|
||||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||
|
||||
// Обработка результата первого потока
|
||||
QObject::connect(scriptWorker, &PayByPhoneScript::finishedWithResult, &app, [account, connectStopOnQuit](const QString &result) {
|
||||
qDebug() << "Получен результат: [" << result << "]";
|
||||
QObject::connect(scriptWorker, &PayByPhoneScript::finishedWithResult, &app,
|
||||
[account, connectStopOnQuit](const QString &result) {
|
||||
qDebug() << "Получен результат: [" << result << "]";
|
||||
|
||||
// Создаем второй поток после завершения первого
|
||||
auto *thread2 = new QThread;
|
||||
auto *scriptWorker2 = new GetLastDaysHistoryScript(account);
|
||||
scriptWorker2->moveToThread(thread2);
|
||||
// Создаем второй поток после завершения первого
|
||||
auto *thread2 = new QThread;
|
||||
auto *scriptWorker2 = new GetLastDaysHistoryScript(account);
|
||||
scriptWorker2->moveToThread(thread2);
|
||||
|
||||
// Запуск второго потока
|
||||
QObject::connect(thread2, &QThread::started, scriptWorker2, &GetLastDaysHistoryScript::start);
|
||||
QObject::connect(scriptWorker2, &GetLastDaysHistoryScript::finished, thread2, &QThread::quit);
|
||||
QObject::connect(scriptWorker2, &GetLastDaysHistoryScript::finished, scriptWorker2, &QObject::deleteLater);
|
||||
QObject::connect(thread2, &QThread::finished, thread2, &QThread::deleteLater);
|
||||
// Запуск второго потока
|
||||
QObject::connect(thread2, &QThread::started, scriptWorker2,
|
||||
&GetLastDaysHistoryScript::start);
|
||||
QObject::connect(scriptWorker2, &GetLastDaysHistoryScript::finished, thread2,
|
||||
&QThread::quit);
|
||||
QObject::connect(scriptWorker2, &GetLastDaysHistoryScript::finished, scriptWorker2,
|
||||
&QObject::deleteLater);
|
||||
QObject::connect(thread2, &QThread::finished, thread2, &QThread::deleteLater);
|
||||
|
||||
// Остановка второго потока при завершении приложения
|
||||
connectStopOnQuit(scriptWorker2, thread2);
|
||||
// Остановка второго потока при завершении приложения
|
||||
connectStopOnQuit(scriptWorker2, thread2);
|
||||
|
||||
thread2->start();
|
||||
});
|
||||
thread2->start();
|
||||
});
|
||||
|
||||
// Остановка первого потока при завершении приложения
|
||||
connectStopOnQuit(scriptWorker, thread);
|
||||
@ -132,12 +138,63 @@ void setupScriptAutoPaymentAndThread(QCoreApplication &app) {
|
||||
}
|
||||
}
|
||||
|
||||
static QFile logFile;
|
||||
static QMutex logMutex;
|
||||
|
||||
void messageHandler(
|
||||
QtMsgType type,
|
||||
const QMessageLogContext &context,
|
||||
const QString &msg
|
||||
) {
|
||||
Q_UNUSED(context) // можно раскомментировать, если нужны file/line/function
|
||||
// Формируем строку с типом и временем
|
||||
const QString timestamp = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
|
||||
QString level;
|
||||
switch (type) {
|
||||
case QtDebugMsg: level = "DEBUG";
|
||||
break;
|
||||
case QtInfoMsg: level = "INFO";
|
||||
break;
|
||||
case QtWarningMsg: level = "WARNING";
|
||||
break;
|
||||
case QtCriticalMsg: level = "CRITICAL";
|
||||
break;
|
||||
case QtFatalMsg: level = "FATAL";
|
||||
break;
|
||||
}
|
||||
|
||||
const QString line = QString("%1 [%2] %3\n").arg(timestamp, level, msg);
|
||||
|
||||
// Записываем в файл (потокобезопасно)
|
||||
{
|
||||
QMutexLocker locker(&logMutex);
|
||||
if (logFile.isOpen()) {
|
||||
QTextStream(&logFile) << line;
|
||||
logFile.flush();
|
||||
}
|
||||
}
|
||||
|
||||
// По желанию — дублировать в консоль
|
||||
QByteArray localMsg = line.toLocal8Bit();
|
||||
fprintf(stderr, "%s", localMsg.constData());
|
||||
|
||||
if (type == QtFatalMsg) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
QApplication app(argc, argv);
|
||||
|
||||
setupWorkerAndThreadHistory(app);
|
||||
setupWorkerAndThread(app);
|
||||
logFile.setFileName("application.log");
|
||||
if (!logFile.open(QIODevice::Append | QIODevice::Text)) {
|
||||
qWarning() << "Не удалось открыть лог-файл для записи";
|
||||
}
|
||||
// Устанавливаем свой обработчик
|
||||
qInstallMessageHandler(messageHandler);
|
||||
|
||||
setupScriptAutoPaymentAndThread(app);
|
||||
// setupWorkerAndThread(app);
|
||||
|
||||
MainWindow window;
|
||||
window.show();
|
||||
|
||||
@ -45,6 +45,7 @@ CREATE TABLE IF NOT EXISTS transactions
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
account_id INTEGER,
|
||||
external_id INTEGER,
|
||||
|
||||
amount REAL,
|
||||
fee REAL,
|
||||
@ -60,9 +61,7 @@ CREATE TABLE IF NOT EXISTS transactions
|
||||
|
||||
bank_name TEXT,
|
||||
bank_time TEXT,
|
||||
|
||||
|
||||
tr_external_id TEXT,
|
||||
bank_tr_external_id TEXT,
|
||||
|
||||
update_time DATETIME,
|
||||
complete_time DATETIME,
|
||||
|
||||
@ -63,7 +63,7 @@ struct TransactionInfo {
|
||||
QString bankName;
|
||||
QString bankTime;
|
||||
|
||||
QString trExternalId;
|
||||
QString bankTrExternalId;
|
||||
|
||||
QDateTime updateTime;
|
||||
QDateTime completeTime;
|
||||
@ -90,7 +90,7 @@ inline QString convertTransactionToString(const TransactionInfo &tx) {
|
||||
if (!tx.bankName.isEmpty()) lines << " bankName: " + tx.bankName; else emptyFields << "bankName";
|
||||
if (!tx.bankTime.isEmpty()) lines << " bankTime: " + tx.bankTime; else emptyFields << "bankTime";
|
||||
if (!tx.name.isEmpty()) lines << " name: " + tx.name; else emptyFields << "name";
|
||||
if (!tx.trExternalId.isEmpty()) lines << " trExternalId: " + tx.trExternalId; else emptyFields << "trExternalId";
|
||||
if (!tx.bankTrExternalId.isEmpty()) lines << " bankTrExternalId: " + tx.bankTrExternalId; else emptyFields << "bankTrExternalId";
|
||||
if (tx.updateTime.isValid()) lines << " updateTime: " + tx.updateTime.toString(Qt::ISODate); else emptyFields << "updateTime";
|
||||
if (tx.completeTime.isValid()) lines << " completeTime: " + tx.completeTime.toString(Qt::ISODate); else emptyFields << "completeTime";
|
||||
if (tx.timestamp.isValid()) lines << " timestamp: " + tx.timestamp.toString(Qt::ISODate); else emptyFields << "timestamp";
|
||||
|
||||
@ -54,7 +54,7 @@ void postDevicesData(const QList<DeviceInfo> &devices) {
|
||||
}
|
||||
|
||||
QHttpPart uniquePart;
|
||||
uniquePart.setHeader(QNetworkRequest::ContentDispositionHeader, R"(form-data; name="uniqueName")");
|
||||
uniquePart.setHeader(QNetworkRequest::ContentDispositionHeader, R"(form-data; name="desktopUniqueName")");
|
||||
uniquePart.setBody("DT88bokcwQ");
|
||||
|
||||
multiPart->append(uniquePart);
|
||||
|
||||
@ -5,36 +5,38 @@
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include "dao/TransactionDAO.h"
|
||||
|
||||
NetworkService::NetworkService(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
NetworkService::~NetworkService() = default;
|
||||
|
||||
// FIXME доделать работу с экстра
|
||||
void NetworkService::addExtra(const QString &key, const QVariant &value) {
|
||||
m_extraData[key] = value;
|
||||
}
|
||||
|
||||
void NetworkService::postAccountsData() {
|
||||
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
void addFormField(QHttpMultiPart *multiPart, const QString &fieldName, const QString &fieldValue) {
|
||||
QHttpPart formField;
|
||||
formField.setHeader(
|
||||
QNetworkRequest::ContentDispositionHeader,QStringLiteral("form-data; name=\"%1\"").arg(fieldName)
|
||||
);
|
||||
formField.setBody(fieldValue.toUtf8());
|
||||
multiPart->append(formField);
|
||||
}
|
||||
|
||||
void addFormMetadata(QHttpMultiPart *multiPart, const QByteArray &fieldValue) {
|
||||
QHttpPart jsonPart;
|
||||
jsonPart.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=UTF-8");
|
||||
jsonPart.setHeader(QNetworkRequest::ContentDispositionHeader, R"(form-data; name="metadata")");
|
||||
|
||||
jsonPart.setBody(m_json);
|
||||
jsonPart.setBody(fieldValue);
|
||||
multiPart->append(jsonPart);
|
||||
}
|
||||
|
||||
|
||||
QHttpPart desktopUniqueName;
|
||||
desktopUniqueName.setHeader(QNetworkRequest::ContentDispositionHeader, R"(form-data; name="desktopUniqueName")");
|
||||
desktopUniqueName.setBody(m_desktopId.toUtf8());
|
||||
multiPart->append(desktopUniqueName);
|
||||
|
||||
|
||||
QHttpPart androidUniqueName;
|
||||
androidUniqueName.setHeader(QNetworkRequest::ContentDispositionHeader, R"(form-data; name="androidUniqueName")");
|
||||
androidUniqueName.setBody(m_deviceId.toUtf8());
|
||||
multiPart->append(androidUniqueName);
|
||||
|
||||
QJsonValue NetworkService::post(QHttpMultiPart *multiPart, const QString &path) {
|
||||
QNetworkAccessManager manager; // создаём внутри потока
|
||||
const QUrl url("http://localhost:9999/api/v1/account/update");
|
||||
const QUrl url(path);
|
||||
const QNetworkRequest request(url);
|
||||
|
||||
QNetworkReply *reply = manager.post(request, multiPart);
|
||||
@ -47,20 +49,71 @@ void NetworkService::postAccountsData() {
|
||||
});
|
||||
loop.exec(); // <- здесь и запускается event-loop потока
|
||||
|
||||
// обрабатываем результат
|
||||
QJsonValue result;
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
const QByteArray raw = reply->readAll();
|
||||
QJsonParseError err;
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(raw, &err);
|
||||
if (err.error == QJsonParseError::NoError && doc.isObject()) {
|
||||
const QJsonObject root = doc.object();
|
||||
qDebug() << "Успешный ответ: " << root.value("success").toBool();
|
||||
if (root.value("success").toBool()) {
|
||||
result = root.value("data");
|
||||
} else {
|
||||
qWarning() << "Ошибка:" << root;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Ошибка:" << reply->errorString();
|
||||
}
|
||||
reply->deleteLater();
|
||||
return result;
|
||||
}
|
||||
|
||||
void NetworkService::postAccountsData() {
|
||||
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
addFormMetadata(multiPart, m_json);
|
||||
addFormField(multiPart, "desktopUniqueName", m_desktopId);
|
||||
addFormField(multiPart, "androidUniqueName", m_deviceId);
|
||||
const bool isSuccess = post(multiPart, "http://localhost:9999/api/v1/account/update").toBool();
|
||||
if (!isSuccess) {
|
||||
qDebug() << "Cant post accounts data";
|
||||
}
|
||||
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void NetworkService::updateTransactionData() {
|
||||
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
addFormMetadata(multiPart, m_json);
|
||||
addFormField(multiPart, "desktopUniqueName", m_desktopId);
|
||||
addFormField(multiPart, "androidUniqueName", m_deviceId);
|
||||
addFormField(multiPart, "lastNumbers", m_extraData["lastNumbers"].toString());
|
||||
|
||||
const bool isSuccess = post(multiPart, "http://localhost:9999/api/v1/transaction/update").toBool();
|
||||
if (!isSuccess) {
|
||||
qDebug() << "Cant update transaction";
|
||||
}
|
||||
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void NetworkService::insertTransactionData() {
|
||||
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
addFormMetadata(multiPart, m_json);
|
||||
addFormField(multiPart, "desktopUniqueName", m_desktopId);
|
||||
addFormField(multiPart, "androidUniqueName", m_deviceId);
|
||||
addFormField(multiPart, "lastNumbers", m_extraData["lastNumbers"].toString());
|
||||
|
||||
const int id = post(multiPart, "http://localhost:9999/api/v1/transaction/insert").toInt();
|
||||
if (id > 0) {
|
||||
const int transactionId = m_extraData["transactionId"].toInt();
|
||||
if (!TransactionDAO::updateExternalTransactionId(transactionId, id)) {
|
||||
qDebug() << "Cant update transaction id";
|
||||
}
|
||||
}
|
||||
emit finished();
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
#include <qhttpmultipart.h>
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
|
||||
class NetworkService final : public QObject {
|
||||
Q_OBJECT
|
||||
@ -16,9 +18,16 @@ public:
|
||||
m_deviceId = deviceId;
|
||||
}
|
||||
|
||||
void addExtra(const QString &key, const QVariant &value);
|
||||
|
||||
public slots:
|
||||
void postAccountsData();
|
||||
|
||||
|
||||
void insertTransactionData();
|
||||
|
||||
void updateTransactionData();
|
||||
|
||||
void stop();
|
||||
|
||||
signals:
|
||||
@ -28,5 +37,9 @@ private:
|
||||
QByteArray m_json;
|
||||
QString m_deviceId;
|
||||
QString m_desktopId;
|
||||
QMap<QString, QVariant> m_extraData = {};
|
||||
bool m_running = true;
|
||||
|
||||
|
||||
QJsonValue post(QHttpMultiPart *multiPart, const QString &path);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user