Commit 79fb9d12 by NitefullWind

1. 实现实体卡激活(软件激活、硬件激活、数据库保存、日志记录)。

parent f6369531
...@@ -34,7 +34,8 @@ SOURCES += main.cpp\ ...@@ -34,7 +34,8 @@ SOURCES += main.cpp\
fmloading.cpp \ fmloading.cpp \
fmsetting.cpp \ fmsetting.cpp \
cardreader.cpp \ cardreader.cpp \
fmmsgwnd.cpp fmmsgwnd.cpp \
fmlogger.cpp
HEADERS += \ HEADERS += \
fmbackup.h \ fmbackup.h \
...@@ -45,7 +46,9 @@ HEADERS += \ ...@@ -45,7 +46,9 @@ HEADERS += \
fmloading.h \ fmloading.h \
fmsetting.h \ fmsetting.h \
cardreader.h \ cardreader.h \
fmmsgwnd.h fmmsgwnd.h \
fmp_logstream.h \
fmlogger.h
FORMS += \ FORMS += \
rechargewnd.ui \ rechargewnd.ui \
......
...@@ -17,7 +17,11 @@ void CardReader::run() ...@@ -17,7 +17,11 @@ void CardReader::run()
_isRunning = true; _isRunning = true;
int port = FMSetting::GetValue("Port", 0).toInt(); int port = FMSetting::GetValue("Port", 0).toInt();
int baud = FMSetting::GetValue("Baud", 115200).toInt(); int baud = FMSetting::GetValue("Baud", 115200).toInt();
ConnectDevice(port, baud); _isRunning &= ConnectDevice(port, baud);
if(!_isRunning) {
return;
}
def_sector = FMSetting::GetValue("DefaultSector", 4).toInt(); def_sector = FMSetting::GetValue("DefaultSector", 4).toInt();
def_pwd = FMSetting::GetValue("DefaultPwd", "ffffffffffff").toString(); def_pwd = FMSetting::GetValue("DefaultPwd", "ffffffffffff").toString();
...@@ -27,10 +31,12 @@ void CardReader::run() ...@@ -27,10 +31,12 @@ void CardReader::run()
_isRunning &= LoadKeyHex(def_sector, def_pwd); _isRunning &= LoadKeyHex(def_sector, def_pwd);
_isRunning &= LoadKeyHex(0, def_pwd); _isRunning &= LoadKeyHex(0, def_pwd);
_isRunning &= LoadKeyHex(sector, password); _isRunning &= LoadKeyHex(sector, password);
_isRunning &= LoadKeyHex(15, "000000000000");
willActiveCard = needActiveCard = "";
while(_isRunning) { while(_isRunning) {
ReadVipNo(); OperatorCard();
Sleep(500); Sleep(300);
} }
} }
...@@ -42,6 +48,7 @@ void CardReader::Stop() ...@@ -42,6 +48,7 @@ void CardReader::Stop()
void CardReader::setError(const QString &error) void CardReader::setError(const QString &error)
{ {
_error = error; _error = error;
FM_ERROR() << error;
emit hadError(_error); emit hadError(_error);
} }
...@@ -111,8 +118,20 @@ bool CardReader::ReadData(qint8 sec, QString &data, qint8 blockNums, bool isHex) ...@@ -111,8 +118,20 @@ bool CardReader::ReadData(qint8 sec, QString &data, qint8 blockNums, bool isHex)
return true; return true;
} }
bool CardReader::ReadVipNo() bool CardReader::OperatorCard()
{ {
// 检查是否需要激活卡
if(needActiveCard != "" && needActiveCard==willActiveCard) {
FM_INFO() << "Active card: " << needActiveCard;
activedSuccess = Active(needActiveCard);
FM_INFO() << "Active card success: " << activedSuccess;
needActiveCard = willActiveCard = lastUUID = "";
waitActive.wakeAll();
}
// 故意鉴权失败,使卡片不用离开读卡器即可再次寻卡
rf_authentication(_handle, 0, 15);
bool isActived = true;
QString data, uuid, vipNo=""; QString data, uuid, vipNo="";
unsigned long snr; unsigned long snr;
if(rf_card(_handle, 0, &snr) != 0) { if(rf_card(_handle, 0, &snr) != 0) {
...@@ -124,23 +143,99 @@ bool CardReader::ReadVipNo() ...@@ -124,23 +143,99 @@ bool CardReader::ReadVipNo()
} }
uuid = data.mid(0, 10); uuid = data.mid(0, 10);
// 验证sector扇区密码是否正确,以区分是否是激活过的卡 // 判断是否还是上一张卡
if(rf_authentication(_handle, 0, sector) != 0) { if(uuid == lastUUID) {
// 重新寻卡 // 同一张卡,直接返回
unsigned long snr; return false;
if(rf_card(_handle, 0, &snr) != 0) { } else {
return false; lastUUID = uuid;
} activedSuccess = false;
// 未激活的卡,从def_sector扇区读取账号 needActiveCard = willActiveCard = "";
if(ReadData(def_sector, data)){ FM_INFO() << "Find new card: " << lastUUID;
vipNo = data.mid(16); }
// 读默认扇区,看是否是激活过的卡(不用rf_authentcation,因为验证密码出错需重新寻卡)
if(ReadData(def_sector, data)) {
if(data == "00000000000000000000000000000000") {
if(ReadData(sector, data, 2, false)) {
vipNo = data;
isActived = true;
}
} else {
// 从def_sector扇区读取账号
if(ReadData(def_sector, data)){
vipNo = data.mid(16);
isActived = false;
needActiveCard = vipNo;
}
} }
} else if(ReadData(sector, data, 2, false)) {
vipNo = data;
} }
FM_INFO() << "Vip No: " << vipNo << " Is actived: " << isActived;
if(vipNo!="") { if(vipNo!="") {
emit hadVipNo(vipNo, uuid); emit hadVipNo(vipNo, uuid, isActived);
} }
return false; return false;
} }
bool CardReader::ActiveCard(QString vipNo)
{
mutex.lock();
willActiveCard = vipNo;
waitActive.wait(&mutex);
mutex.unlock();
return activedSuccess;
}
bool CardReader::Active(const QString &vipNo)
{
// 将卡号写入sec的扇区
if(!LoadKeyHex(sector, def_pwd)) {
return false;
}
// 鉴权
if(rf_authentication(_handle, 0, sector) != 0){
setError(QString("%1扇区密码错误").arg(sector));
return false;
}
// 写入卡号
char* writeData = vipNo.toLatin1().toHex().mid(0,32).data();
if(rf_write_hex(_handle, sector*4, writeData) !=0 ) {
setError("写入卡号失败");
return false;
}
// 修改密码
QByteArray tmpData = password.toLatin1();
unsigned char wkey[7];
ZeroMemory(wkey, 7);
a_hex(tmpData.data(), wkey, 12);
if(rf_changeb3(_handle, sector, wkey, 0, 0, 0, 1, 0, wkey) != 0) {
setError("修改密码失败");
return false;
}
// 删除原扇区内容
LoadKeyHex(def_sector, def_pwd);
// 鉴权
if(rf_authentication(_handle, 0, def_sector) != 0) {
setError(QString("%1扇区密码错误").arg(def_sector));
return false;
}
// 初始化为0
char zeroData[33] = "00000000000000000000000000000000";
if(rf_write_hex(_handle, def_sector*4, zeroData) !=0 ){
setError("擦除原数据失败");
return false;
}
rf_beep(_handle, 30);
rf_halt(_handle);
return true;
}
void CardReader::ClearInfo()
{
willActiveCard = needActiveCard = lastUUID = "";
activedSuccess = false;
}
#ifndef CARDREADER_H #ifndef CARDREADER_H
#define CARDREADER_H #define CARDREADER_H
#include "fmlogger.h"
#include <QThread> #include <QThread>
#include <windows.h> #include <windows.h>
#include <QMutex>
#include <QWaitCondition>
class CardReader : public QThread class CardReader : public QThread
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit CardReader(QObject *parent = 0); explicit CardReader(QObject *parent = 0);
~CardReader(); ~CardReader();
...@@ -18,25 +22,13 @@ public: ...@@ -18,25 +22,13 @@ public:
bool ConnectDevice(int port, int baud); bool ConnectDevice(int port, int baud);
void DisConnectDevice(); void DisConnectDevice();
bool LoadKeyHex(qint8 sec, const QString &password); bool ActiveCard(QString vipNo);
/**
* @brief ReadData
* @param sec 扇区号0-15
* @param data 数据
* @param blockNums 块数量
* @param isHex 是否是16进制
* @return
*/
bool ReadData(qint8 sec, QString &data, qint8 blockNums=1, bool isHex=true);
bool ActiveCard();
void ClearInfo();
signals: signals:
void hadError(const QString &error); void hadError(const QString &error);
void hadVipNo(const QString &vipNo, const QString &uuid); void hadVipNo(const QString &vipNo, const QString &uuid, bool isActived);
public slots:
protected: protected:
void run(); void run();
...@@ -49,9 +41,28 @@ private: ...@@ -49,9 +41,28 @@ private:
qint8 def_sector, sector; qint8 def_sector, sector;
QString def_pwd, password; QString def_pwd, password;
QString willActiveCard, needActiveCard, lastUUID;
QMutex mutex;
QWaitCondition waitActive;
bool activedSuccess;
void setError(const QString& error); void setError(const QString& error);
bool ReadVipNo(); bool OperatorCard();
bool LoadKeyHex(qint8 sec, const QString &password);
/**
* @brief ReadData
* @param sec 扇区号0-15
* @param data 数据
* @param blockNums 块数量
* @param isHex 是否是16进制
* @return
*/
bool ReadData(qint8 sec, QString &data, qint8 blockNums=1, bool isHex=true);
bool Active(const QString &vipNo);
}; };
#endif // CARDREADER_H #endif // CARDREADER_H
#include "fmbackup.h" #include "fmbackup.h"
#include "fmlogger.h"
#include <QSqlDatabase> #include <QSqlDatabase>
#include <QSqlQuery> #include <QSqlQuery>
#include <QSqlRecord> #include <QSqlRecord>
...@@ -6,7 +7,6 @@ ...@@ -6,7 +7,6 @@
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QApplication> #include <QApplication>
#include <QDebug>
FMBackup::FMBackup() FMBackup::FMBackup()
{ {
...@@ -36,9 +36,9 @@ bool FMBackup::connect() ...@@ -36,9 +36,9 @@ bool FMBackup::connect()
isOk =_db.open(); isOk =_db.open();
} }
qDebug() << "连接数据库:" << dbname; FM_INFO() << "连接数据库:" << dbname;
if(!isOk) { if(!isOk) {
qDebug() << "连接失败:" << _db.lastError().text(); setError("连接数据库失败:" + _db.lastError().text());
} }
return isOk; return isOk;
...@@ -51,39 +51,60 @@ bool FMBackup::createTable(const QString &dbname) ...@@ -51,39 +51,60 @@ bool FMBackup::createTable(const QString &dbname)
_db.open(); _db.open();
QSqlQuery query(_db); QSqlQuery query(_db);
// 创建表 // 创建表
bool isOk = query.exec("create table tbl_card(card_no char(20) NOT NULL PRIMARY KEY, inner_no char(20), active_date char(10), active_time char(8))"); bool isOk = query.exec("create table tbl_recharge("
"id integer PRIMARY KEY autoincrement,"
"card_no char(20) NOT NULL,"
"inner_no char(20),"
"recharge_amount double,"
"after_amount double,"
"fm_id char(25),"
"recharge_date char(10), "
"recharge_time char(8))");
qDebug() << "创建数据库:" << dbname; FM_DEBUG() << "创建表:" << dbname;
if (!isOk) { if (!isOk) {
qDebug() << "创建数据库失败:" << query.lastError().text(); setError("创建表失败:" + query.lastError().text());
} }
return isOk; return isOk;
} }
bool FMBackup::insert(QString card_no, QString inner_no, QString date, QString time) bool FMBackup::insert(QString card_no, QString inner_no,
double recharge_amount, double after_amount,
QString fm_id,
QString date, QString time)
{ {
if(!_db.isOpen()) { if(!_db.isOpen()) {
connect(); connect();
} }
QSqlQuery query(_db); QSqlQuery query(_db);
bool isOk = query.exec(QString("insert into tbl_card('card_no','inner_no', 'active_date', 'active_time') values('%1','%2', '%3', '%4');") bool isOk = query.exec(QString("insert into tbl_recharge("
"'card_no',"
"'inner_no',"
"'recharge_amount',"
"'after_amount',"
"'fm_id',"
"'recharge_date',"
"'recharge_time') values('%1','%2', '%3', '%4', '%5', '%6', '%7');")
.arg(card_no) .arg(card_no)
.arg(inner_no) .arg(inner_no)
.arg(recharge_amount)
.arg(after_amount)
.arg(fm_id)
.arg(date) .arg(date)
.arg(time)); .arg(time));
if(!isOk) { if(!isOk) {
qDebug() << "插入失败:" << query.lastError().text(); setError("插入失败:" + query.lastError().text());
} }
return isOk; return isOk;
} }
QSqlQuery FMBackup::cardQuery(QString date) const QSqlQuery FMBackup::cardQuery(QString date)
{ {
QSqlQuery query(_db); QSqlQuery query(_db);
bool isOk = query.exec(QString("select * from tbl_card where 'date'='%1'").arg(date)); bool isOk = query.exec(QString("select * from tbl_recharge where 'date'='%1'").arg(date));
if(!isOk) { if(!isOk) {
qDebug() << "查询数据时出现错误:" << query.lastError().text(); setError("查询数据时出现错误:" + query.lastError().text());
} }
return query; return query;
} }
...@@ -92,6 +113,17 @@ bool FMBackup::reset() ...@@ -92,6 +113,17 @@ bool FMBackup::reset()
{ {
QSqlQuery query(_db); QSqlQuery query(_db);
bool isOk = query.exec("VACUUM"); bool isOk = query.exec("VACUUM");
qDebug() << "数据库重置: " << isOk; setError("数据库重置: " + isOk ? "成功" : "失败");
return isOk; return isOk;
} }
void FMBackup::setError(const QString &error)
{
_error = error;
FM_ERROR() << error;
}
QString FMBackup::lastError() const
{
return _error;
}
...@@ -8,16 +8,20 @@ class FMBackup ...@@ -8,16 +8,20 @@ class FMBackup
public: public:
static FMBackup* instance(); static FMBackup* instance();
QSqlDatabase database() { return _db;} QSqlDatabase database() { return _db;}
bool insert(QString card_no, QString inner_no, QString date, QString time); bool insert(QString card_no, QString inner_no, double recharge_amount, double after_amount, QString fm_id, QString date, QString time);
QSqlQuery cardQuery(QString date) const; QSqlQuery cardQuery(QString date);
bool reset(); bool reset();
QString lastError() const;
private: private:
FMBackup(); FMBackup();
QSqlDatabase _db; QSqlDatabase _db;
QString _error;
bool connect(); bool connect();
bool createTable(const QString &dbname); bool createTable(const QString &dbname);
void setError(const QString &error);
}; };
#endif // FMBACKUP_H #endif // FMBACKUP_H
#include "fmloading.h" #include "fmloading.h"
#include "ui_fmloading.h" #include "ui_fmloading.h"
FMLoading::FMLoading(QDialog *parent) : FMLoading::FMLoading(QDialog *parent) :
...@@ -10,7 +10,7 @@ FMLoading::FMLoading(QDialog *parent) : ...@@ -10,7 +10,7 @@ FMLoading::FMLoading(QDialog *parent) :
setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint); setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
setAttribute(Qt::WA_TranslucentBackground, true); setAttribute(Qt::WA_TranslucentBackground, true);
movie = new QMovie(":/loading.gif"); movie = new QMovie(":/img/loading.gif");
movie->start(); movie->start();
connect(movie, SIGNAL(finished()), movie, SLOT(start())); connect(movie, SIGNAL(finished()), movie, SLOT(start()));
ui->loading_lbl->setMovie(movie); ui->loading_lbl->setMovie(movie);
......
#include "fmlogger.h"
#include "fmsetting.h"
#include <QApplication>
#include <QDateTime>
#include <QFile>
#include <QDir>
FMLogger::FMLogger(QObject *parent) : QObject(parent),
_file(nullptr)
{
}
FMLogger::~FMLogger()
{
if(_file != nullptr) {
_file->close();
delete _file;
_file = nullptr;
}
}
FMLogger *FMLogger::Instance()
{
static FMLogger logger;
return &logger;
}
QIODevice *FMLogger::getIODevice()
{
if(_file == nullptr) {
QString fileName = _NewFileName();
_file = new QFile(fileName);
qDebug() << "New File: " << fileName;
_file->open(QIODevice::Append);
}
return _file;
}
QString FMLogger::GetLogPath()
{
QString path = FMSetting::GetValue("LogPath", qApp->applicationDirPath()+"/log").toString();
path.replace("\\", "/");
QDir log_dir;
if (!log_dir.isAbsolutePath(path)) {
path = qApp->applicationDirPath() + "/" + path;
}
return path;
}
QString FMLogger::_NewFileName()
{
QString log_path = GetLogPath();
QDir log_dir(log_path);
if (!log_dir.exists()) {
if (log_dir.mkdir(log_path)) {
qDebug() << "Create log dir:" << log_path;
}
else {
qDebug() << "Create log dir" << log_path << "failed!";
}
}
QString fileName = log_path + "/" + qApp->applicationName() + "_" +QString::number(QDateTime::currentMSecsSinceEpoch()) + ".log";
return fileName;
}
#ifndef FMLOGGER_H
#define FMLOGGER_H
#include "fmp_logstream.h"
#include <QObject>
class QFile;
class FMLogger : public QObject
{
Q_OBJECT
public:
enum {
LOG_ERROR = 1, LOG_WARNING, LOG_INFO, LOG_DEBUG
};
static FMLogger *Instance();
QIODevice *getIODevice();
QString GetLogPath();
~FMLogger();
private:
explicit FMLogger(QObject *parent = 0);
QString _NewFileName();
QFile *_file;
};
#define FMLOG(level, ioDevice) ((ioDevice == nullptr) ? \
FMPNullLogStream(level, __FILE__, __FUNCTION__, __LINE__) :\
FMPLogStream(level, __FILE__, __FUNCTION__, __LINE__, ioDevice))
#define FM_DEBUG() FMLOG(FMLogger::LOG_DEBUG, FMLogger::Instance()->getIODevice())
#define FM_INFO() FMLOG(FMLogger::LOG_INFO, FMLogger::Instance()->getIODevice())
#define FM_WARN() FMLOG(FMLogger::LOG_WARNING, FMLogger::Instance()->getIODevice())
#define FM_ERROR() FMLOG(FMLogger::LOG_ERROR, FMLogger::Instance()->getIODevice())
#endif // FMLOGGER_H
...@@ -25,12 +25,6 @@ ...@@ -25,12 +25,6 @@
background: transparent; background: transparent;
} }
#close_btn {
min-width: 30px; min-height: 30px;
max-width: 30px; max-height: 30px;
border-image: url(&quot;:/img/btn_alert_close.png&quot;);
}
#alertIconLab #alertIconLab
{ {
color: rgb(0, 0, 0); color: rgb(0, 0, 0);
...@@ -93,6 +87,19 @@ ...@@ -93,6 +87,19 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="close_btn">
<property name="maximumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>
......
#include "fmnetwork.h" #include "fmnetwork.h"
#include "fmlogger.h"
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkReply> #include <QNetworkReply>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QEventLoop> #include <QEventLoop>
#include <QTimer> #include <QTimer>
#include <QDebug>
FMNetwork::FMNetwork(QObject *parent) : FMNetwork::FMNetwork(QObject *parent) :
QObject(parent), QObject(parent),
...@@ -23,8 +23,8 @@ FMNetwork::~FMNetwork() ...@@ -23,8 +23,8 @@ FMNetwork::~FMNetwork()
bool FMNetwork::send(const QString &url, const QByteArray &reqData, QByteArray &rspData, QString &error) bool FMNetwork::send(const QString &url, const QByteArray &reqData, QByteArray &rspData, QString &error)
{ {
bool isOk = false; bool isOk = false;
qDebug() << "Send Url: " << url; FM_INFO() << "Send Url: " << url;
qDebug() << "Send Data: " << reqData; FM_INFO() << "Send Data: " << reqData;
_req->setUrl(url); _req->setUrl(url);
......
#ifndef FMP_LOGGERSTREAM_H
#define FMP_LOGGERSTREAM_H
#include <QDebug>
#include <QDateTime>
class FMPLogStream : public QDebug
{
public:
enum {
ERROR = 1, WARNING, INFO, DEBUG
};
explicit FMPLogStream(short level, const char* file, const char* func, int line, QIODevice* d = 0)
: QDebug(d),
_level(level),
_file(file),
_func(func),
_line(line),
_device(d)
{
_lvmap[ERROR] = "[ERROR]";
_lvmap[WARNING] = "[WARNING]";
_lvmap[INFO] = "[INFO]";
_lvmap[DEBUG] = "[DEBUG]";
}
~FMPLogStream()
{
if (this->_device) {
QDebug::operator <<(endl);
}
}
template <typename T>
QDebug & operator<<(const T& t)
{
qDebug() << t;
QDebug & stream = *(this);
if (!_device) {
stream = qDebug();
}
QString extra;
if (_level != INFO) {
QString filename(_file);
filename = filename.section("\\", -1);
filename = filename.section("/", -1);
extra += QString("%1(%2)").arg(filename).arg(QString::number(_line));
extra += QString("%1:").arg(_func);
}
QString s = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
s.append(_lvmap[_level]);
stream.noquote() << s << extra << t;
return stream;
}
protected:
int _level;
QMap<int, QString> _lvmap;
const char * _file;
const char * _func;
int _line;
QIODevice* _device;
};
class FMPNullLogStream : public FMPLogStream
{
public:
explicit FMPNullLogStream(short level, const char* file, const char* func, int line)
: FMPLogStream(level, file, func, line)
{}
};
#endif // FMP_LOGSTREAM_H
#include "fmvip.h" #include "fmvip.h"
#include "fmlogger.h"
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QJsonParseError> #include <QJsonParseError>
#include <QJsonDocument> #include <QJsonDocument>
...@@ -12,65 +13,49 @@ FMVip::FMVip(QObject *parent) : QObject(parent) ...@@ -12,65 +13,49 @@ FMVip::FMVip(QObject *parent) : QObject(parent)
void FMVip::login(const QString &vipNo, const QString &innerCode, QJsonObject &rspObj) void FMVip::login(const QString &vipNo, const QString &innerCode, QJsonObject &rspObj)
{ {
QJsonObject reqJob; QJsonObject reqObj;
reqJob["appId"] = APP_ID; reqObj["fm_cmd"] = "member_check_request";
reqJob["business_date"] = QDate::currentDate().toString("yyyyMMdd"); reqObj["member_sign"] = vipNo;
reqJob["t"] = QString::number(QDateTime::currentMSecsSinceEpoch()); reqObj["inner_code"] = innerCode;
reqJob["fm_cmd"] = "member_check_request"; reqObj["member_type"] = (int)memberType(vipNo);
reqJob["partner_id"] = PARTNER_ID; sendToServer(reqObj, rspObj);
reqJob["store_id"] = "117017";
reqJob["pos_id"] = "8888";
reqJob["operator_id"] = "8888";
reqJob["member_sign"] = vipNo;
reqJob["inner_code"] = innerCode;
reqJob["member_type"] = (int)memberType(vipNo);
QJsonDocument jsonDoc(reqJob);
QString signStr = sign(reqJob);
QString url = QString("http://member.lxj.sandload.cn/member/service/restful/pos?sign=%1").arg(signStr);
QByteArray rspData;
QString error;
QJsonParseError jsonError;
QJsonDocument rspJsonDoc;
if(networker.send(url, jsonDoc.toJson(), rspData, error))
{
qDebug() << "Server Response:" << QString::fromUtf8(rspData);
rspJsonDoc = QJsonDocument::fromJson(rspData, &jsonError);
if(jsonError.error == QJsonParseError::NoError) {
rspObj = rspJsonDoc.object();
} else {
rspObj["statuc_code"] = 101;
rspObj["msg"] = jsonError.errorString();
}
} else {
rspObj["status_code"] = 102;
rspObj["msg"] = error;
}
} }
void FMVip::recharge(const QString &fm_open_id, int amount, QJsonObject &rspObj) void FMVip::recharge(const QString &fm_open_id, int amount, QJsonObject &rspObj)
{ {
QJsonObject reqJob; QJsonObject reqObj;
reqJob["appId"] = APP_ID; reqObj["fm_cmd"] = "order_recharge_request";
reqJob["business_date"] = QDate::currentDate().toString("yyyyMMdd"); reqObj["trans_id"] = createTransId("117017", "8888");
reqJob["t"] = QString::number(QDateTime::currentMSecsSinceEpoch());
reqJob["fm_cmd"] = "order_recharge_request";
reqJob["partner_id"] = PARTNER_ID;
reqJob["store_id"] = "117017";
reqJob["pos_id"] = "8888";
reqJob["operator_id"] = "8888";
reqJob["trans_id"] = createTransId("117017", "8888");
QJsonObject transObj; QJsonObject transObj;
transObj["account"] = fm_open_id; transObj["account"] = fm_open_id;
transObj["amount"] = amount; transObj["amount"] = amount;
transObj["cash_amount"] = amount; transObj["cash_amount"] = amount;
reqJob["transaction"] = transObj; reqObj["transaction"] = transObj;
sendToServer(reqObj, rspObj);
}
void FMVip::reversal(const QString &fmId)
{
QJsonObject reqObj;
reqObj["fm_cmd"] = "order_correct_request";
reqObj["fm_id"] = fmId;
QJsonObject rspObj;
sendToServer(reqObj, rspObj);
}
void FMVip::sendToServer(QJsonObject &reqObj, QJsonObject &rspObj)
{
reqObj["appId"] = APP_ID;
reqObj["business_date"] = QDate::currentDate().toString("yyyyMMdd");
reqObj["t"] = QString::number(QDateTime::currentMSecsSinceEpoch());
reqObj["partner_id"] = PARTNER_ID;
reqObj["store_id"] = "117017";
reqObj["pos_id"] = "8888";
reqObj["operator_id"] = "8888";
QJsonDocument jsonDoc(reqJob); QJsonDocument jsonDoc(reqObj);
QString signStr = sign(reqJob); QString signStr = sign(reqObj);
QString url = QString("http://member.lxj.sandload.cn/member/service/restful/pos?sign=%1").arg(signStr); QString url = QString("http://member.lxj.sandload.cn/member/service/restful/pos?sign=%1").arg(signStr);
QByteArray rspData; QByteArray rspData;
...@@ -79,17 +64,22 @@ void FMVip::recharge(const QString &fm_open_id, int amount, QJsonObject &rspObj) ...@@ -79,17 +64,22 @@ void FMVip::recharge(const QString &fm_open_id, int amount, QJsonObject &rspObj)
QJsonDocument rspJsonDoc; QJsonDocument rspJsonDoc;
if(networker.send(url, jsonDoc.toJson(), rspData, error)) if(networker.send(url, jsonDoc.toJson(), rspData, error))
{ {
qDebug() << "Server Response:" << QString::fromUtf8(rspData); FM_INFO() << "Server Response:" << QString::fromUtf8(rspData);
rspJsonDoc = QJsonDocument::fromJson(rspData, &jsonError); rspJsonDoc = QJsonDocument::fromJson(rspData, &jsonError);
if(jsonError.error == QJsonParseError::NoError) { if(jsonError.error == QJsonParseError::NoError) {
rspObj = rspJsonDoc.object(); rspObj = rspJsonDoc.object();
if(rspObj.contains("errcode")) {
rspObj["status_code"] = rspObj["errcode"];
rspObj["msg"] = rspObj["errmsg"];
}
} else { } else {
rspObj["statuc_code"] = 101; rspObj["status_code"] = 101;
rspObj["msg"] = jsonError.errorString(); rspObj["msg"] = jsonError.errorString();
} }
} else { } else {
rspObj["status_code"] = 102; rspObj["status_code"] = 300;
rspObj["msg"] = error; rspObj["msg"] = error;
FM_ERROR() << "Network error: " << error;
} }
} }
...@@ -117,7 +107,6 @@ FMVip::MemberType FMVip::memberType(const QString &vipNo) const ...@@ -117,7 +107,6 @@ FMVip::MemberType FMVip::memberType(const QString &vipNo) const
QString FMVip::sign(const QJsonObject &reqJob) const QString FMVip::sign(const QJsonObject &reqJob) const
{ {
qDebug() << __FUNCTION__;
// 解析JSON插入MAP中按字典排序 // 解析JSON插入MAP中按字典排序
QMap<QString, QString> mapData; QMap<QString, QString> mapData;
...@@ -142,7 +131,7 @@ QString FMVip::sign(const QJsonObject &reqJob) const ...@@ -142,7 +131,7 @@ QString FMVip::sign(const QJsonObject &reqJob) const
QByteArray bt; QByteArray bt;
bt.append(sb); bt.append(sb);
qDebug() << "Sign String: " << bt; FM_INFO() << "Sign String: " << bt;
QByteArray md5Bt = QCryptographicHash::hash(bt, QCryptographicHash::Md5); QByteArray md5Bt = QCryptographicHash::hash(bt, QCryptographicHash::Md5);
return md5Bt.toHex(); return md5Bt.toHex();
......
...@@ -25,8 +25,10 @@ public: ...@@ -25,8 +25,10 @@ public:
void login(const QString &vipNo, const QString &innerCode, QJsonObject &rspObj); void login(const QString &vipNo, const QString &innerCode, QJsonObject &rspObj);
void recharge(const QString &fm_open_id, int amount, QJsonObject &rspObj); void recharge(const QString &fm_open_id, int amount, QJsonObject &rspObj);
void reversal(const QString &fmId);
private: private:
void sendToServer(QJsonObject &reqObj, QJsonObject &rspObj);
QString createTransId(const QString &storeId, const QString posId) const; QString createTransId(const QString &storeId, const QString posId) const;
MemberType memberType(const QString &vipNo) const; MemberType memberType(const QString &vipNo) const;
QString sign(const QJsonObject &reqJob) const; QString sign(const QJsonObject &reqJob) const;
......
...@@ -2,11 +2,12 @@ ...@@ -2,11 +2,12 @@
#include "ui_rechargewnd.h" #include "ui_rechargewnd.h"
#include "fmsetting.h" #include "fmsetting.h"
#include "cardreader.h" #include "cardreader.h"
#include "fmbackup.h"
#include "fmmsgwnd.h" #include "fmmsgwnd.h"
#include "fmvip.h" #include "fmvip.h"
#include <QDateTime>
#include <QJsonObject> #include <QJsonObject>
#include <QButtonGroup> #include <QButtonGroup>
#include <QStyle>
#include <QDebug> #include <QDebug>
RechargeWnd::RechargeWnd(QDialog *parent) : RechargeWnd::RechargeWnd(QDialog *parent) :
...@@ -18,6 +19,7 @@ RechargeWnd::RechargeWnd(QDialog *parent) : ...@@ -18,6 +19,7 @@ RechargeWnd::RechargeWnd(QDialog *parent) :
ui->setupUi(this); ui->setupUi(this);
initUi(); initUi();
initReader(); initReader();
FMBackup::instance();
connect(_cardReader, &CardReader::hadVipNo, this, &RechargeWnd::onHadVipNo); connect(_cardReader, &CardReader::hadVipNo, this, &RechargeWnd::onHadVipNo);
} }
...@@ -59,8 +61,10 @@ void RechargeWnd::initUi() ...@@ -59,8 +61,10 @@ void RechargeWnd::initUi()
void RechargeWnd::clearUi() void RechargeWnd::clearUi()
{ {
card_no = inner_no = _fm_open_id = "";
ui->card_label->setText("未知"); ui->card_label->setText("未知");
ui->max_recharge_label->setText("0.00"); ui->max_recharge_label->setText("0.00");
ui->amount_label->setText("0.00");
ui->amount_edit->setText("0.00"); ui->amount_edit->setText("0.00");
ui->recharge_info_label->clear(); ui->recharge_info_label->clear();
foreach (QAbstractButton *btn, _amountBtnGroup->buttons()) { foreach (QAbstractButton *btn, _amountBtnGroup->buttons()) {
...@@ -84,11 +88,14 @@ void RechargeWnd::initReader() ...@@ -84,11 +88,14 @@ void RechargeWnd::initReader()
void RechargeWnd::onHadError(const QString &error) void RechargeWnd::onHadError(const QString &error)
{ {
setIsBusy(false);
FMMsgWnd::FailureWnd(error); FMMsgWnd::FailureWnd(error);
} }
void RechargeWnd::onHadVipNo(const QString &vipNo, const QString &uuid) void RechargeWnd::onHadVipNo(const QString &vipNo, const QString &uuid, bool isActived)
{ {
_fm_open_id = card_no = inner_no = "";
_needActived = !isActived;
clearUi(); clearUi();
setIsBusy(true); setIsBusy(true);
QJsonObject job; QJsonObject job;
...@@ -96,8 +103,17 @@ void RechargeWnd::onHadVipNo(const QString &vipNo, const QString &uuid) ...@@ -96,8 +103,17 @@ void RechargeWnd::onHadVipNo(const QString &vipNo, const QString &uuid)
setIsBusy(false); setIsBusy(false);
if(job["status_code"] != 100) { if(job["status_code"] != 100) {
FMMsgWnd::FailureWnd(job["msg"].toString()); FMMsgWnd::FailureWnd(job["msg"].toString());
_cardReader->ClearInfo();
} else { } else {
card_no = vipNo;
inner_no = uuid;
ui->card_label->setText(vipNo); ui->card_label->setText(vipNo);
double amount = job["amount"].toInt()/100.0;
ui->amount_label->setText(QString::number(amount, 'f', 2));
_fm_open_id = job["fm_unique_id"].toString();
double min_recharge = job["min_recharge_value"].toInt()/100.0; double min_recharge = job["min_recharge_value"].toInt()/100.0;
double max_recharge = job["max_recharge_value"].toInt()/100.0; double max_recharge = job["max_recharge_value"].toInt()/100.0;
QString max_recharge_str = QString::number(max_recharge, 'f', 2); QString max_recharge_str = QString::number(max_recharge, 'f', 2);
...@@ -121,5 +137,50 @@ void RechargeWnd::onHadVipNo(const QString &vipNo, const QString &uuid) ...@@ -121,5 +137,50 @@ void RechargeWnd::onHadVipNo(const QString &vipNo, const QString &uuid)
void RechargeWnd::on_recharge_btn_clicked() void RechargeWnd::on_recharge_btn_clicked()
{ {
_cardReader int recharge_amount = (int)ui->amount_edit->text().toDouble()*100;
setIsBusy(true);
QJsonObject job;
_fmvip->recharge(_fm_open_id, recharge_amount, job);
if(job["status_code"] == 100) {
double after_amount = job["after_value"].toInt()/100.0;
QString fm_id = job["fm_id"].toString();
QDateTime dateTime = QDateTime::currentDateTime();
// 备份
bool isSuccess = FMBackup::instance()->insert(card_no, inner_no,
recharge_amount/100, after_amount,
fm_id, dateTime.toString("yyyy-MM-dd"),
dateTime.toString("hh:mm:ss"));
if(!isSuccess) {
ui->recharge_info_label->setText(FMBackup::instance()->lastError());
}
// 激活
if(isSuccess && _needActived) {
isSuccess = _cardReader->ActiveCard(ui->card_label->text());
}
setIsBusy(false);
// 是否成功
if(isSuccess) {
_needActived = false;
QString after_amount_str = QString::number(after_amount, 'f', 2);
ui->amount_label->setText(after_amount_str);
ui->recharge_info_label->setText("充值成功!");
ui->amount_edit->setText("0.00");
_fm_open_id = card_no = inner_no = "";
} else {
// 硬件激活失败,发起冲正
_fmvip->reversal(job["fm_id"].toString());
}
} else {
setIsBusy(false);
ui->recharge_info_label->setText("充值失败:"+job["msg"].toString());
}
} }
...@@ -31,11 +31,13 @@ private: ...@@ -31,11 +31,13 @@ private:
CardReader *_cardReader; CardReader *_cardReader;
FMVip *_fmvip; FMVip *_fmvip;
bool _needActived;
QString card_no, inner_no, _fm_open_id;
private slots: private slots:
void onAmountBtnClicked(QAbstractButton* button); void onAmountBtnClicked(QAbstractButton* button);
void onHadError(const QString &error); void onHadError(const QString &error);
void onHadVipNo(const QString &vipNo, const QString &uuid); void onHadVipNo(const QString &vipNo, const QString &uuid, bool isActived);
void on_recharge_btn_clicked(); void on_recharge_btn_clicked();
}; };
......
...@@ -106,6 +106,7 @@ QPushButton#recharge_btn:hover { ...@@ -106,6 +106,7 @@ QPushButton#recharge_btn:hover {
} }
#recharge_info_label { #recharge_info_label {
max-width: 200;
color: rgb(255, 0, 0); color: rgb(255, 0, 0);
}</string> }</string>
</property> </property>
...@@ -313,9 +314,30 @@ QPushButton#recharge_btn:hover { ...@@ -313,9 +314,30 @@ QPushButton#recharge_btn:hover {
</item> </item>
<item> <item>
<widget class="QLabel" name="recharge_info_label"> <widget class="QLabel" name="recharge_info_label">
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>400</width>
<height>16777215</height>
</size>
</property>
<property name="text"> <property name="text">
<string/> <string/>
</property> </property>
<property name="textFormat">
<enum>Qt::AutoText</enum>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment