Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
F
fmp_vip
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xiaojing.zhang
fmp_vip
Commits
3ff6ecbf
Commit
3ff6ecbf
authored
Oct 31, 2017
by
NitefullWind
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1. 对接服务端充值接口。 2. 修改各接口返回字段。
parent
5c233792
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
85 additions
and
38 deletions
+85
-38
fmvip/fmvipdispatcher.cpp
+6
-0
fmvip/global.h
+21
-14
fmvip/task/fmtask.cpp
+1
-1
fmvip/task/taskfinal.cpp
+5
-4
fmvip/task/taskfund.cpp
+20
-9
fmvip/task/taskfund.h
+1
-1
fmvip/task/tasklogin.cpp
+7
-1
fmvip/task/taskpay.cpp
+4
-4
fmvip/task/taskrefund.cpp
+7
-2
fmvip/task/taskrefund.h
+2
-0
fmvip/windows/forms/fmvipfund.ui
+5
-0
tests/testplugin/tst_testplugin.cpp
+5
-1
version.h
+1
-1
No files found.
fmvip/fmvipdispatcher.cpp
View file @
3ff6ecbf
...
...
@@ -13,6 +13,7 @@
#include "taskothers.h"
#include "taskfinal.h"
#include "taskrefund.h"
#include "taskfund.h"
#include "tasksetstoreinfo.h"
#include <ctkPluginContext.h>
#undef StartService
...
...
@@ -105,6 +106,11 @@ void FMVipDispatcher::doTask(const QByteArray &reqData, QByteArray &rspData)
session
.
clear
();
break
;
}
case
FM_Fund
:
{
TaskFund
taskFund
(
jsonObj
);
rspData
=
taskFund
.
doTask
();
break
;
}
default
:
rspData
=
QString
::
fromLocal8Bit
(
"{
\"
msg:
\"
:
\"
未知的请求类型
\"
}"
).
toUtf8
();
break
;
...
...
fmvip/global.h
View file @
3ff6ecbf
...
...
@@ -7,26 +7,30 @@
// 商家信息
//! 绿篮子
#define APP_ID "T013"
#define KEY_CODE "a35e33c8-e6f2-4107-8670-a69a85adf85b"
#define PARTNER_ID "f92b8997-40c7-4622-af3b-512fd49d6113"
//
#define APP_ID "T013"
//
#define KEY_CODE "a35e33c8-e6f2-4107-8670-a69a85adf85b"
//
#define PARTNER_ID "f92b8997-40c7-4622-af3b-512fd49d6113"
////! 一茶一座
//#define APP_ID "T014"
//#define KEY_CODE "a440d553-87d3-4fcd-b59a-5ec9ce7c4157"
//#define PARTNER_ID "df2f90b0-eece-402c-820d-ba8ac56c4687"
//! 加移
#define APP_ID "T019"
#define KEY_CODE "059e15e7-19a6-480f-8b5f-3a082a5b553e"
#define PARTNER_ID "c3e82ff2-6285-4823-8e3f-7ec880ae7119"
// 请求类型的枚举值
enum
FM_TYPE
{
FM_Set_Store_Info
=
1000
,
FM_Login
=
1001
,
FM_Fund
=
1002
,
FM_Pay
=
1003
,
FM_Refund
=
1004
,
FM_Final
=
1007
,
FM_Coupon
=
1009
,
FM_Fund
,
FM_Order_Revoke
,
FM_QR_Pay
=
10031
,
FM_QR_Refund
=
10041
,
...
...
@@ -53,7 +57,8 @@ const FMReqUrlMap::value_type FMReqUrlMapPairs[] =
FMReqUrlMap
::
value_type
(
FM_Final
,
"order"
),
FMReqUrlMap
::
value_type
(
FM_Refund_Pay
,
"refund"
),
FMReqUrlMap
::
value_type
(
FM_Refund_Order
,
"correct"
),
FMReqUrlMap
::
value_type
(
FM_Coupon
,
"ordercoupon"
)
FMReqUrlMap
::
value_type
(
FM_Coupon
,
"ordercoupon"
),
FMReqUrlMap
::
value_type
(
FM_Fund
,
"recharge"
)
};
const
FMReqUrlMap
ReqUrl
(
FMReqUrlMapPairs
,
FMReqUrlMapPairs
+
(
sizeof
FMReqUrlMapPairs
/
sizeof
FMReqUrlMapPairs
[
0
]));
#endif
...
...
@@ -76,7 +81,6 @@ struct PP{
FM_Type
=
"FM_Type"
;
TransId
=
"trans_id"
;
OrderId
=
"order_id"
;
fmTransId
=
"fm_trans_id"
;
Fm_order_id
=
"fm_order_id"
;
Member_sign
=
"member_sign"
;
Account
=
"account"
;
...
...
@@ -96,7 +100,7 @@ struct PP{
Score
=
"score"
;
StatusCode
=
"status
C
ode"
;
StatusCode
=
"status
_c
ode"
;
Msg
=
"msg"
;
Prompt
=
"prompt"
;
...
...
@@ -109,16 +113,17 @@ struct PP{
Transaction
=
"transactions"
;
OrderAmount
=
"order_amount"
;
PaidAmount
=
"paid_amount"
;
DisAmount
=
"dis_amount"
;
UndisAmount
=
"undis_amount"
;
NeedAmount
=
"need_amount"
;
StandardAmount
=
"standard_amount"
;
Fm_id
=
"fm_id"
;
Settlement
=
"settlement"
;
Fm_transId
=
"fm_transI
d"
;
Fm_trans_id
=
"fm_trans_i
d"
;
Pro_amount
=
"pro_amount"
;
Pay_amount
=
"pay_amount"
;
Pay_
ids
=
"pay_ids
"
;
Pay_
list
=
"pay_list
"
;
Pay_id
=
"pay_id"
;
Pay_str
=
"pay_str"
;
Paid_total_amount
=
"paid_total_amount"
;
...
...
@@ -159,7 +164,6 @@ struct PP{
QString
FM_Type
;
QString
TransId
;
QString
OrderId
;
QString
fmTransId
;
QString
Fm_order_id
;
QString
Member_sign
;
QString
Account
;
...
...
@@ -194,17 +198,18 @@ struct PP{
QString
OrderAmount
;
QString
NeedAmount
;
QString
PaidAmount
;
QString
DisAmount
;
QString
UndisAmount
;
QString
StandardAmount
;
QString
Fm_id
;
QString
Settlement
;
QString
Fm_transI
d
;
QString
Fm_trans_i
d
;
QString
Pro_amount
;
QString
Pay_amount
;
// 支付方式
QString
Pay_
ids
;
QString
Pay_
list
;
QString
Pay_id
;
QString
Pay_str
;
QString
Paid_total_amount
;
...
...
@@ -243,6 +248,7 @@ const static PP PosProps;
typedef
std
::
map
<
QString
,
QString
>
PropsMap
;
const
PropsMap
::
value_type
PropsMapPairs
[]
=
{
PropsMap
::
value_type
(
PosProps
.
StatusCode
,
"statusCode"
),
PropsMap
::
value_type
(
PosProps
.
Fm_cmd
,
"reqType"
),
PropsMap
::
value_type
(
PosProps
.
Member_sign
,
"code"
),
PropsMap
::
value_type
(
PosProps
.
StoreId
,
"storeId"
),
...
...
@@ -263,11 +269,12 @@ const PropsMap::value_type PropsMapPairs[] =
PropsMap
::
value_type
(
PosProps
.
OrderAmount
,
"totalAmount"
),
PropsMap
::
value_type
(
PosProps
.
Pay_id
,
"typeModeFlag"
),
PropsMap
::
value_type
(
PosProps
.
Pay_amount
,
"amount"
),
PropsMap
::
value_type
(
PosProps
.
Pay_
ids
,
"payList"
),
PropsMap
::
value_type
(
PosProps
.
Pay_
list
,
"payList"
),
PropsMap
::
value_type
(
PosProps
.
Products
,
"productList"
),
PropsMap
::
value_type
(
PosProps
.
ProductId
,
"productId"
),
PropsMap
::
value_type
(
PosProps
.
ConsumeNum
,
"consumeNum"
),
PropsMap
::
value_type
(
PosProps
.
Price
,
"price"
),
PropsMap
::
value_type
(
PosProps
.
ChargeAmount
,
"payAmount"
),
};
static
PropsMap
PosToServerProps
(
PropsMapPairs
,
PropsMapPairs
+
(
sizeof
(
PropsMapPairs
)
/
sizeof
(
PropsMapPairs
[
0
])));
...
...
@@ -328,7 +335,7 @@ enum {
};
// 返回错误信息的json
#define ErrorMsgJson "{\"status
C
ode\":%1,\"msg\":\"%2\",\"prompt\":0}"
#define ErrorMsgJson "{\"status
_c
ode\":%1,\"msg\":\"%2\",\"prompt\":0}"
#define ErrorNeedPayCode "fmv:请使用支付码付款"
typedef
std
::
map
<
const
int
,
const
char
*>
FMErrorMap
;
...
...
fmvip/task/fmtask.cpp
View file @
3ff6ecbf
...
...
@@ -117,7 +117,7 @@ bool FMTask::sendToServer(bool isShowMsg)
QByteArray
data
=
json
.
toJson
(
QJsonDocument
::
Compact
);
#ifdef FMTEST
url
=
"http://
micro-service.sandload.cn/member-pos
/pos/member/"
+
ReqUrl
.
at
(
FM_Type
());
url
=
"http://
115.159.124.30:8732
/pos/member/"
+
ReqUrl
.
at
(
FM_Type
());
#else
url
=
FMPVipSettings
::
instance
()
->
getServerUrl
()
+
"/"
+
ReqUrl
.
at
(
FM_Type
());
#endif
...
...
fmvip/task/taskfinal.cpp
View file @
3ff6ecbf
...
...
@@ -111,7 +111,7 @@ void TaskFinal::packageServerReq()
payArray
.
append
(
payObj
);
}
dataObj
[
ServerProps
(
PosProps
.
Pay_
ids
)]
=
payArray
;
dataObj
[
ServerProps
(
PosProps
.
Pay_
list
)]
=
payArray
;
serverReqJsonObj
[
"data"
]
=
dataObj
;
...
...
@@ -209,13 +209,14 @@ void TaskFinal::packagePOSRsp()
p
.
push_back
(
PosProps
.
StatusCode
);
p
.
push_back
(
PosProps
.
Msg
);
p
.
push_back
(
PosProps
.
Fm_order_id
);
p
.
push_back
(
PosProps
.
Print1
);
p
.
push_back
(
PosProps
.
Print2
);
foreach
(
auto
prop
,
p
)
{
posRspJsonObj
[
prop
]
=
getServerJsonValue
(
prop
);
}
posRspJsonObj
[
PosProps
.
Prompt
]
=
1
;
QJsonObject
ext
;
ext
[
PosProps
.
Print
]
=
getServerJsonValue
(
PosProps
.
Print1
);
posRspJsonObj
[
"ext"
]
=
ext
;
if
(
getServerJsonValue
(
PosProps
.
StatusCode
).
toInt
()
==
FM_API_SUCCESS
)
{
_order
->
setSettled
(
true
);
...
...
fmvip/task/taskfund.cpp
View file @
3ff6ecbf
#
include
"taskfund.h"
#include "fmvipfund.h"
#include "tasklogin.h"
#include "items/storeinfo.h"
#include "dbop.h"
TaskFund
::
TaskFund
(
QJsonObject
&
jsonObj
,
QObject
*
parent
)
:
FMTask
(
jsonObj
,
FM_Fund
,
0
,
parent
)
...
...
@@ -8,15 +10,19 @@ TaskFund::TaskFund(QJsonObject &jsonObj, QObject *parent)
}
QByteArray
TaskFund
::
doTask
()
void
TaskFund
::
packagePOSReq
()
{
FMItem
::
StoreInfo
storeInfo
;
DBOP
::
GetLastItem
(
&
storeInfo
);
posReqJsonObj
=
storeInfo
.
toJson
(
QStringList
(),
posReqJsonObj
);
preTask
=
new
TaskLogin
(
posReqJsonObj
,
_session
,
this
);
preTask
->
session
()
->
addData
(
PosProps
.
FM_Type
,
FM_Fund
);
QByteArray
loginRst
=
preTask
->
doTask
();
preTask
->
doTask
();
if
(
preTask
->
error
()
!=
FM_API_SUCCESS
)
{
return
loginRst
;
setError
(
preTask
->
error
())
;
}
return
FMTask
::
doTask
();
}
void
TaskFund
::
setWindow
()
...
...
@@ -30,12 +36,18 @@ void TaskFund::setWindow()
void
TaskFund
::
packageServerReq
()
{
serverReqJsonObj
[
ServerProps
(
PosProps
.
TransId
)]
=
getPosJsonValue
(
PosProps
.
Trans
Id
);
serverReqJsonObj
[
ServerProps
(
PosProps
.
TransId
)]
=
getPosJsonValue
(
PosProps
.
Order
Id
);
QJsonObject
trans
;
trans
[
ServerProps
(
PosProps
.
Fm_open_id
)]
=
session
()
->
data
(
PosProps
.
Fm_open_id
).
toString
();
trans
[
ServerProps
(
PosProps
.
ChargeAmount
)]
=
session
()
->
data
(
PosProps
.
ChargeAmount
).
toInt
();
trans
[
ServerProps
(
PosProps
.
CashAmount
)]
=
session
()
->
data
(
PosProps
.
ChargeAmount
).
toInt
();
serverReqJsonObj
[
ServerProps
(
PosProps
.
Transaction
)]
=
trans
;
QJsonObject
payCash
;
payCash
[
ServerProps
(
PosProps
.
Amount
)]
=
session
()
->
data
(
PosProps
.
ChargeAmount
).
toInt
();
payCash
[
ServerProps
(
PosProps
.
TransId
)]
=
getPosJsonValue
(
PosProps
.
OrderId
);
payCash
[
ServerProps
(
PosProps
.
Type_code
)]
=
"10001"
;
QJsonArray
payList
;
payList
.
append
(
payCash
);
trans
[
ServerProps
(
PosProps
.
Pay_list
)]
=
payList
;
serverReqJsonObj
[
"data"
]
=
trans
;
}
void
TaskFund
::
packagePOSRsp
()
...
...
@@ -48,12 +60,11 @@ void TaskFund::packagePOSRsp()
foreach
(
QString
prop
,
p
)
{
posRspJsonObj
[
prop
]
=
getServerJsonValue
(
prop
);
}
posRspJsonObj
[
PosProps
.
Prompt
]
=
1
;
posRspJsonObj
[
PosProps
.
Fm_open_id
]
=
session
()
->
data
(
PosProps
.
Fm_open_id
).
toString
();
}
void
TaskFund
::
onFund
()
{
sendToServer
();
_window
->
close
();
_window
->
accept
();
}
fmvip/task/taskfund.h
View file @
3ff6ecbf
...
...
@@ -8,7 +8,7 @@ class TaskFund : public FMTask
public
:
explicit
TaskFund
(
QJsonObject
&
jsonObj
,
QObject
*
parent
=
0
);
QByteArray
doTask
();
void
packagePOSReq
();
void
setWindow
();
void
packageServerReq
();
void
packagePOSRsp
();
...
...
fmvip/task/tasklogin.cpp
View file @
3ff6ecbf
...
...
@@ -39,10 +39,16 @@ void TaskLogin::packagePOSRsp()
p
.
push_back
(
PosProps
.
StatusCode
);
p
.
push_back
(
PosProps
.
Msg
);
p
.
push_back
(
PosProps
.
Fm_open_id
);
p
.
push_back
(
PosProps
.
Amount
);
p
.
push_back
(
PosProps
.
Score
);
p
.
push_back
(
PosProps
.
Sex
);
p
.
push_back
(
PosProps
.
Birthday
);
p
.
push_back
(
PosProps
.
Phone
);
p
.
push_back
(
PosProps
.
Address
);
p
.
push_back
(
PosProps
.
Email
);
foreach
(
QString
prop
,
p
)
{
posRspJsonObj
[
prop
]
=
getServerJsonValue
(
prop
);
}
posRspJsonObj
[
PosProps
.
Prompt
]
=
0
;
}
void
TaskLogin
::
onLogin
()
...
...
fmvip/task/taskpay.cpp
View file @
3ff6ecbf
...
...
@@ -170,10 +170,9 @@ void TaskPay::packagePOSRsp()
posRspJsonObj
[
PosProps
.
StatusCode
]
=
status
;
posRspJsonObj
[
PosProps
.
Msg
]
=
getServerJsonValue
(
PosProps
.
Msg
);
posRspJsonObj
[
PosProps
.
Prompt
]
=
0
;
posRspJsonObj
[
PosProps
.
Settlement
]
=
1
;
posRspJsonObj
[
PosProps
.
Fm_open_id
]
=
fm_open_id
;
posRspJsonObj
[
PosProps
.
Fm_order_id
]
=
fm_order_id
;
posRspJsonObj
[
PosProps
.
Fm_trans_id
]
=
fm_order_id
;
Order
*
order
=
new
Order
(
this
);
DBOP
::
GetOrderByOrderId
(
orderId
,
order
);
...
...
@@ -226,8 +225,9 @@ void TaskPay::packagePOSRsp()
delete
pay
;
}
}
posRspJsonObj
[
PosProps
.
Paid_total_amount
]
=
totalPaid
;
posRspJsonObj
[
PosProps
.
Pay_ids
]
=
pay_ids
;
posRspJsonObj
[
PosProps
.
PaidAmount
]
=
totalPaid
;
posRspJsonObj
[
PosProps
.
Pay_list
]
=
pay_ids
;
posRspJsonObj
[
PosProps
.
DisAmount
]
=
0
;
delete
order
;
}
...
...
fmvip/task/taskrefund.cpp
View file @
3ff6ecbf
...
...
@@ -12,6 +12,7 @@
TaskRefund
::
TaskRefund
(
QJsonObject
&
jsonObj
,
Session
*
session
,
QObject
*
parent
)
:
FMTask
(
jsonObj
,
FM_Refund
,
session
,
parent
)
,
_refundAmount
(
0
)
{
}
...
...
@@ -26,7 +27,6 @@ void TaskRefund::packagePOSReq()
QString
orderId
=
getPosJsonValue
(
PosProps
.
OrderId
).
toString
();
session
()
->
addData
(
PosProps
.
OrderId
,
orderId
);
//! TODO 需要从其他数据库查询营业日、门店信息等。
FMItem
::
StoreInfo
storeInfo
;
bool
isOk
=
DBOP
::
GetLastItem
(
&
storeInfo
);
if
(
isOk
)
{
...
...
@@ -48,7 +48,9 @@ void TaskRefund::packageServerReq()
void
TaskRefund
::
packagePOSRsp
()
{
posRspJsonObj
[
PosProps
.
StatusCode
]
=
FM_API_SUCCESS
;
posRspJsonObj
[
PosProps
.
Msg
]
=
"Success"
;
posRspJsonObj
[
"refund_amount"
]
=
_refundAmount
;
}
void
TaskRefund
::
onRefundPay
(
int
DBID
)
...
...
@@ -71,6 +73,7 @@ void TaskRefund::onRefundPay(int DBID)
if
(
isOk
)
{
orderPointer
->
setPaidAmount
(
orderPointer
->
paidAmount
()
-
payPointer
->
refundAmount
());
isOk
=
DBOP
::
Save
(
orderPointer
.
data
());
_refundAmount
+=
payPointer
->
payAmount
();
}
qobject_cast
<
FMVipRefund
*>
(
_window
)
->
refresh
();
...
...
@@ -93,6 +96,8 @@ void TaskRefund::onRefundOrder(int DBID)
orderPointer
->
setPaidAmount
(
0
);
DBOP
::
Save
(
orderPointer
.
data
());
qobject_cast
<
FMVipRefund
*>
(
_window
)
->
refresh
();
_refundAmount
=
orderPointer
->
paidAmount
();
}
else
{
QString
msg
=
searchJsonValue
(
rspObj
,
PosProps
.
Msg
).
toString
();
FMMsgWnd
::
FailureWnd
(
msg
,
_window
);
...
...
fmvip/task/taskrefund.h
View file @
3ff6ecbf
...
...
@@ -18,6 +18,8 @@ private:
private
:
void
onRefundPay
(
int
DBID
);
void
onRefundOrder
(
int
DBID
);
int
_refundAmount
;
};
#endif // TASKREFUND_H
fmvip/windows/forms/fmvipfund.ui
View file @
3ff6ecbf
...
...
@@ -592,6 +592,11 @@ QPushButton#fund_btn:hover {
</layout>
</widget>
<layoutdefault
spacing=
"6"
margin=
"11"
/>
<tabstops>
<tabstop>
amount_edit
</tabstop>
<tabstop>
fund_btn
</tabstop>
<tabstop>
close_btn
</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
tests/testplugin/tst_testplugin.cpp
View file @
3ff6ecbf
#include <QtTest>
#include <QCoreApplication>
#include <QMessageBox>
#include "fmvipdispatcher.h"
...
...
@@ -52,7 +53,7 @@ void TestPlugin::test_dotask_data()
QTest
::
newRow
(
"SetStoreInfo_need_posId"
)
<<
QByteArray
(
"{
\"
fm_cmd
\"
: 1000,
\"
store_id
\"
:
\"
fm9999
\"
,
\"
pos_id
\"
:
\"\"
,
\"
business_date
\"
:
\"
20171016
\"
,
\"
operator_id
\"
:
\"
001
\"
}"
);
QTest
::
newRow
(
"SetStoreInfo_notnull_posId"
)
<<
QByteArray
(
"{
\"
fm_cmd
\"
: 1000,
\"
store_id
\"
:
\"
fm9999
\"
,
\"
business_date
\"
:
\"
20171016
\"
,
\"
operator_id
\"
:
\"
001
\"
}"
);
QTest
::
newRow
(
"SetStoreInfo_error_type"
)
<<
QByteArray
(
"{
\"
fm_cmd
\"
: 1000,
\"
store_id
\"
:
\"
fm9999
\"
,
\"
pos_id
\"
: 1,
\"
business_date
\"
:
\"
20171016
\"
,
\"
operator_id
\"
:
\"
001
\"
}"
);
QTest
::
newRow
(
"Login"
)
<<
QByteArray
(
"{
\"
fm_cmd
\"
: 1001
,
\"
member_sign
\"
:
\"
12345
\"
}"
);
QTest
::
newRow
(
"Login"
)
<<
QByteArray
(
"{
\"
fm_cmd
\"
: 1001}"
);
QTest
::
newRow
(
"Pay"
)
<<
QByteArray
(
"{"
"
\"
fm_cmd
\"
: 1003,"
"
\"
order_amount
\"
:9000,"
...
...
@@ -76,6 +77,7 @@ void TestPlugin::test_dotask_data()
" ]"
"}"
);
QTest
::
newRow
(
"Order"
)
<<
QByteArray
(
"{
\"
fm_cmd
\"
: 1007,
\"
order_id
\"
:
\"
20171018001
\"
}"
);
QTest
::
newRow
(
"Fund"
)
<<
QByteArray
(
"{
\"
fm_cmd
\"
: 1002,
\"
order_id
\"
:
\"
20171018001
\"
}"
);
}
void
TestPlugin
::
test_dotask
()
...
...
@@ -86,6 +88,8 @@ void TestPlugin::test_dotask()
fmvip
.
doTask
(
reqData
,
rspData
);
qDebug
()
<<
"RspData: "
<<
rspData
.
data
();
QMessageBox
::
information
(
nullptr
,
"Return to POS"
,
QString
(
rspData
));
}
QTEST_MAIN
(
TestPlugin
)
...
...
version.h
View file @
3ff6ecbf
...
...
@@ -5,7 +5,7 @@
#define VER_MINOR 1
#define VER_REVISION 0
#define VER_BUILD 1
6
#define VER_BUILD 1
7
//! Convert version numbers to string
#define _STR(S) #S
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment