Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Z
zhichan
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
蒋勇
zhichan
Commits
9b35fe57
Commit
9b35fe57
authored
Nov 10, 2020
by
wangyong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: (agriculture) 磐农项目 推易代账推企服通
parent
7862186a
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
156 additions
and
57 deletions
+156
-57
icp-deliver/app/base/db/models/agriculture/accounting.js
+31
-0
icp-deliver/app/base/db/models/agriculture/accountset.js
+0
-5
icp-deliver/app/base/service/impl/agriculture/accountsetSve.js
+1
-1
icp-deliver/app/base/service/impl/agriculture/servicebillSve.js
+85
-29
icp-deliver/app/base/utils/ydzClient.js
+37
-20
icp-deliver/app/config/settings.js
+2
-2
No files found.
icp-deliver/app/base/db/models/agriculture/accounting.js
View file @
9b35fe57
...
@@ -25,7 +25,38 @@ module.exports = (db, DataTypes) => {
...
@@ -25,7 +25,38 @@ module.exports = (db, DataTypes) => {
mobile
:
{
//电话
mobile
:
{
//电话
allowNull
:
true
,
allowNull
:
true
,
type
:
DataTypes
.
INTEGER
type
:
DataTypes
.
INTEGER
},
accCode
:
{
//会计组织的code
allowNull
:
false
,
type
:
DataTypes
.
STRING
},
accName
:
{
//会计组织名称
allowNull
:
false
,
type
:
DataTypes
.
STRING
},
accaddress
:
{
//会计组织地址
allowNull
:
false
,
type
:
DataTypes
.
STRING
},
workingYears
:
{
// 工作年限
allowNull
:
false
,
type
:
DataTypes
.
INTEGER
},
accCredentials
:
{
// 会计证书:初级会 计、中级会计、高 级会计师、注册会 计师、注册税务师、 ACCA、CMA
allowNull
:
false
,
type
:
DataTypes
.
JSON
},
accAccount
:
{
//会计账号
allowNull
:
false
,
type
:
DataTypes
.
STRING
},
note
:
{
//其他信息
allowNull
:
true
,
type
:
DataTypes
.
STRING
}
}
},
{
},
{
paranoid
:
false
,
//假的删除
paranoid
:
false
,
//假的删除
underscored
:
true
,
underscored
:
true
,
...
...
icp-deliver/app/base/db/models/agriculture/accountset.js
View file @
9b35fe57
...
@@ -103,11 +103,6 @@ module.exports = (db, DataTypes) => {
...
@@ -103,11 +103,6 @@ module.exports = (db, DataTypes) => {
allowNull
:
false
,
allowNull
:
false
,
type
:
DataTypes
.
STRING
type
:
DataTypes
.
STRING
},
},
isBuild
:
{
//是否建账
allowNull
:
false
,
type
:
DataTypes
.
BOOLEAN
,
defaultValue
:
true
},
accountBook
:
{
//账套信息
accountBook
:
{
//账套信息
allowNull
:
true
,
allowNull
:
true
,
type
:
DataTypes
.
JSON
type
:
DataTypes
.
JSON
...
...
icp-deliver/app/base/service/impl/agriculture/accountsetSve.js
View file @
9b35fe57
...
@@ -11,7 +11,7 @@ class AccountsetService extends ServiceBase {
...
@@ -11,7 +11,7 @@ class AccountsetService extends ServiceBase {
}
}
async
create
(
obj
)
{
async
create
(
obj
)
{
const
res
=
await
this
.
dao
.
upd
ate
(
obj
);
const
res
=
await
this
.
dao
.
cre
ate
(
obj
);
return
res
;
return
res
;
}
}
}
}
...
...
icp-deliver/app/base/service/impl/agriculture/servicebillSve.js
View file @
9b35fe57
...
@@ -10,6 +10,7 @@ class ServicebillService extends ServiceBase {
...
@@ -10,6 +10,7 @@ class ServicebillService extends ServiceBase {
constructor
()
{
constructor
()
{
super
(
"agriculture"
,
ServiceBase
.
getDaoName
(
ServicebillService
));
super
(
"agriculture"
,
ServiceBase
.
getDaoName
(
ServicebillService
));
this
.
accountsetSve
=
System
.
getObject
(
"service.agriculture.accountsetSve"
);
this
.
accountsetSve
=
System
.
getObject
(
"service.agriculture.accountsetSve"
);
this
.
accountingSve
=
System
.
getObject
(
"service.agriculture.accountingSve"
);
}
}
async
findAndCountAll
(
obj
)
{
async
findAndCountAll
(
obj
)
{
...
@@ -28,32 +29,25 @@ class ServicebillService extends ServiceBase {
...
@@ -28,32 +29,25 @@ class ServicebillService extends ServiceBase {
async
updateAndPush
(
obj
)
{
//服务单分配会计推企服通回传会计信息、并推易代账新建帐套
async
updateAndPush
(
obj
)
{
//服务单分配会计推企服通回传会计信息、并推易代账新建帐套
const
res
=
await
this
.
dao
.
update
(
obj
);
const
res
=
await
this
.
dao
.
update
(
obj
);
const
findService
=
await
this
.
dao
.
findOne
({
bizId
:
obj
.
bizId
});
const
findService
=
await
this
.
dao
.
findOne
({
bizId
:
obj
.
bizId
});
const
findAccount
=
await
this
.
accountingSve
.
findOne
({
id
:
obj
.
accountantEmployeeId
});
if
(
findService
)
{
if
(
findService
)
{
let
data
=
{
//推企服通回传会计信息;
custName
:
findService
.
contactName
,
//客户名称
const
data
=
this
.
mappingQiFuTong
(
findService
,
findAccount
);
corpName
:
findService
.
companyInfo
.
companyName
,
//企业名称
taxiationArea
:
findService
.
companyInfo
.
companyArea
,
//报税地区
taxIndustryId
:
findService
.
companyInfo
.
industry
,
//行业
serviceTypeEnum
:
"ACCOUTING"
,
// 服务类型:枚举型,包括ACCOUTING-记账服务、INDUSTRY_COMMERCE-工商服务、BOTH-记账与工商服务。
taxNo
:
findService
.
companyInfo
.
taxpayerNumber
,
// 税号
accountantEmployeeId
:
obj
.
accountantAgentAccountId
,
//所属会计
taxClaimMethodEnum
:
"TAX_DECLARATION"
,
//申报方式:TAX_DECLARATION-税款申报;ZERO_DECLARATION-零申报;
isBuild
:
true
//是否建账
}
console
.
log
(
data
);
//TODO: 推企服通回传会计信息
// dev gsbweb.qifu-dev.gongsibao.com/api/opreceive/service/notice
// pro gsbweb.qifu.gongsibao.com/api/opreceive/service/notice
// pushQiFuTong({"actionType":"accountingInfo","actionBody": backData});
await
TOQFT
.
getClientByType
(
"pannong"
).
pushQiFuTong
(
obj
.
username
,
{
"actionType"
:
"accountingInfo"
,
"actionBody"
:
data
});
await
TOQFT
.
getClientByType
(
"pannong"
).
pushQiFuTong
(
obj
.
username
,
{
"actionType"
:
"accountingInfo"
,
"actionBody"
:
data
});
// TODO: 分配会计并推送易代账新建帐套 回传后新建本地帐套
//分配会计并推送易代账新建帐套
const
accountset
=
await
ydzPush
.
pushYiDaZhang
(
user
,
data
);
const
setData
=
this
.
mappingYDZ
(
findService
);
const
res
=
await
this
.
accountsetSve
.
create
(
accountset
);
const
pushYDZResult
=
await
ydzPush
.
pushYiDaZhang
(
setData
)
//新建本地帐套
const
createData
=
this
.
mappingSetToLocalCreate
(
pushYDZResult
,
setData
.
accountBook
);
delete
createData
.
id
;
//删除易代账返回ID
const
createAccountset
=
await
this
.
accountsetSve
.
create
(
createData
);
console
.
log
(
createAccountset
);
//
TODO:
推送企服通帐套信息
//推送企服通帐套信息
// pushQiFuTong({"actionType":"booksInfo","actionBody": res}
);
const
toQFTSetData
=
this
.
mappingSetToQiFuTong
(
pushYDZResult
,
findService
);
await
TOQFT
.
getClientByType
(
"pannong"
).
pushQiFuTong
(
obj
.
username
,
{
"actionType"
:
"booksInfo"
,
"actionBody"
:
res
});
await
TOQFT
.
getClientByType
(
"pannong"
).
pushQiFuTong
(
obj
.
username
,
{
"actionType"
:
"booksInfo"
,
"actionBody"
:
toQFTSetData
});
}
else
{
}
else
{
console
.
log
(
'查无此单:'
+
obj
.
bizId
);
console
.
log
(
'查无此单:'
+
obj
.
bizId
);
}
}
...
@@ -62,26 +56,87 @@ class ServicebillService extends ServiceBase {
...
@@ -62,26 +56,87 @@ class ServicebillService extends ServiceBase {
async
updateAndFeedback
(
obj
)
{
//服务单审核并推送企服通
async
updateAndFeedback
(
obj
)
{
//服务单审核并推送企服通
const
res
=
await
this
.
dao
.
update
(
obj
);
const
res
=
await
this
.
dao
.
update
(
obj
);
const
findOne
=
await
this
.
dao
.
findOne
({
bizId
:
obj
.
bizId
});
const
findOne
=
await
this
.
dao
.
findOne
({
id
:
obj
.
id
});
const
deadline
=
moment
(
findOne
.
updated_at
).
add
(
findOne
.
quantity
,
'years'
);
let
backData
=
{};
let
backData
=
{};
if
(
findOne
)
{
if
(
findOne
)
{
backData
.
bizId
=
findOne
.
bizId
;
backData
.
bizId
=
findOne
.
bizId
;
backData
.
auditResult
=
findOne
.
status
;
backData
.
auditResult
=
findOne
.
status
;
backData
.
orderNo
=
findOne
.
orderNo
;
if
(
backData
.
auditResult
==
1
)
{
//审核通过
if
(
backData
.
auditResult
==
1
)
{
//审核通过
backData
.
serviceStartTime
=
findOne
.
updated_at
;
backData
.
serviceStartTime
=
moment
(
findOne
.
updated_at
).
format
(
'YYYY-MM-DD'
)
;
backData
.
serviceEndTime
=
deadline
;
backData
.
serviceEndTime
=
moment
(
moment
(
findOne
.
updated_at
).
add
(
findOne
.
quantity
,
'years'
)).
format
(
'YYYY-MM-DD'
)
;
}
}
if
(
backData
.
auditResult
==
2
)
{
// 审核未通过
if
(
backData
.
auditResult
==
2
)
{
// 审核未通过
backData
.
note
=
findOne
.
feedback_notes
;
backData
.
note
=
findOne
.
feedback_notes
;
}
}
//TODO: 推送企服通
//推送企服通
// pushQiFuTong({"actionType":"feedback","actionBody": backData});
await
TOQFT
.
getClientByType
(
"pannong"
).
pushQiFuTong
(
obj
.
username
,
{
"actionType"
:
"feedback"
,
"actionBody"
:
backData
});
await
TOQFT
.
getClientByType
(
"pannong"
).
pushQiFuTong
(
obj
.
username
,
{
"actionType"
:
"feedback"
,
"actionBody"
:
backData
});
}
else
{
}
else
{
console
.
log
(
'查无此单:'
+
obj
.
bizId
);
console
.
log
(
'查无此单:'
+
obj
.
bizId
);
}
}
}
}
mappingQiFuTong
(
findService
,
findAccount
)
{
let
data
=
{
bizId
:
findService
.
bizId
,
accInfo
:
{
accCode
:
findAccount
.
accCode
,
accName
:
findAccount
.
accName
,
accaddress
:
findAccount
.
accaddress
,
workingYears
:
findAccount
.
workingYears
,
accCredentials
:
findAccount
.
accCredentials
,
accAccount
:
findAccount
.
accAccount
,
accountingName
:
findAccount
.
name
,
note
:
findAccount
.
note
||
'无'
}
}
return
data
;
}
mappingYDZ
(
findService
)
{
let
setData
=
{
custName
:
findService
.
contactName
,
//客户名称
corpName
:
findService
.
companyInfo
.
companyName
,
//企业名称
taxiationArea
:
findService
.
companyInfo
.
companyArea
,
//报税地区
taxIndustryId
:
findService
.
companyInfo
.
industry
,
//行业
serviceTypeEnum
:
"ACCOUTING"
,
// 服务类型:枚举型,包括ACCOUTING-记账服务、INDUSTRY_COMMERCE-工商服务、BOTH-记账与工商服务。
taxNo
:
findService
.
companyInfo
.
taxpayerNumber
,
// 税号
accountantEmployeeId
:
findService
.
accountantAgentAccountId
,
//所属会计 易代账ID
taxClaimMethodEnum
:
"TAX_DECLARATION"
,
//申报方式:TAX_DECLARATION-税款申报;ZERO_DECLARATION-零申报;
isBuild
:
true
,
//是否建账
accountBook
:
{
name
:
`gsb_
${
findService
.
bizId
}
`
,
//账套名称
acctgSystemId
:
findService
.
companyInfo
.
acctgSystemId
,
//会计制度;包括:10001=2013小企业会计准则;10002=2007企业会计准则;10003=民间非营利组织会计制度;10004=工会会计制度
openingPeriod
:
moment
().
year
(),
//开账期间
taxpayerTypeEnum
:
findService
.
taxpayerType
,
//纳税性质,枚举包括:NORMAL_TAXPAYER=一般纳税人;SMALL_TAXPAYER=小规模纳税人
acctgTransGroupEnum
:
'ACCTG'
//凭证类别,枚举包括:ACCTG=记账凭证等;RECEIPT_PAYMENT_TRANSFER=收付转凭证
}
}
return
setData
;
}
mappingSetToQiFuTong
(
setInfo
,
findService
)
{
let
toQFTSetData
=
{
bizId
:
findService
.
bizId
,
subjectId
:
setInfo
.
custId
,
bookId
:
setInfo
.
assocTenantId
,
bkDomainName
:
setInfo
.
bkDomainName
,
contactName
:
setInfo
.
customer
.
contactName
,
contactMobile
:
setInfo
.
customer
.
contactMobile
,
timeUnit
:
findService
.
timeUnit
,
quantity
:
findService
.
quantity
,
note
:
findService
.
note
||
'无'
,
companyInfo
:
findService
.
companyInfo
}
return
toQFTSetData
;
}
mappingSetToLocalCreate
(
setInfo
,
accountBook
)
{
let
createData
=
{};
for
(
let
key
in
setInfo
.
customer
)
{
if
(
key
==
'tenantId'
)
{
createData
.
manageId
=
setInfo
.
customer
[
key
];
}
createData
[
key
]
=
setInfo
.
customer
[
key
];
}
createData
.
accountBook
=
accountBook
;
return
createData
;
}
}
}
module
.
exports
=
ServicebillService
;
module
.
exports
=
ServicebillService
;
\ No newline at end of file
icp-deliver/app/base/utils/ydzClient.js
View file @
9b35fe57
const
axios
=
require
(
"axios"
);
const
axios
=
require
(
"axios"
);
const
settings
=
require
(
"../../config/settings"
);
const
settings
=
require
(
"../../config/settings"
);
const
system
=
require
(
"../system"
);
const
system
=
require
(
"../system"
);
const
centerChannelUrl
=
settings
.
centerChannel
Url
();
const
ydzUrl
=
settings
.
ydz
Url
();
/**
/**
* 请求易代账
* 请求易代账
* 封装 获取 userpin token
* 封装 获取 userpin token
*/
*/
const
pushYiDaZhang
=
async
(
data
=
{})
=>
{
const
pushYiDaZhang
=
async
(
data
=
{})
=>
{
const
ydzUrl
=
settings
.
ydzUrl
();
const
{
appKey
,
appSecret
}
=
settings
.
ydzKey
();
const
{
appKey
,
appSecret
}
=
settings
.
ydzKey
();
// const openToken = getOpenTokenByAppKey(appKey, appSecret);
// const openToken =
await
getOpenTokenByAppKey(appKey, appSecret);
const
header
=
{
const
header
=
{
"Content-Type"
:
"application/json"
,
"Content-Type"
:
"application/json"
,
"appKey"
:
appKey
,
"appKey"
:
appKey
,
"appSecret"
:
appSecret
,
"appSecret"
:
appSecret
,
"openToken"
:
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NfdG9rZW4iOi
I4MjE3MjExMS0xOGIzLTQ4YzgtYTUzMi01ZjVkZjE3ZmM0MTMiLCJzdWIiOiJpc3YiLCJhdWQiOiJpc3YiLCJuYmYiOjE2MDQ2NTcxNDEsImFwcElkIjoiMTA2NSIsInNjb3BlIjoiYXV0aF9hbGwiLCJpc3MiOiJjaGFuamV0IiwiZXhwIjoxNjA1MTc1NTQxLCJ1c2VySWQiOiI2MTAwMDQzMjU3NSIsImlhdCI6MTYwNDY1NzE0MSwib3JnSWQiOiI5MDAwMTIwNTYyNSIsIm9yZ0FjY291bnQiOiJ1MzEzbWN2czR5d2EifQ.j-97chbDAVZQ060EYaLqC6UldYdgdsA4FFrKmCT2tbo
"
"openToken"
:
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NfdG9rZW4iOi
JlYzQ4OTFjZS05OWIzLTQzNjAtYjMyMi04MzUyOWMxMGQ5ZjQiLCJzdWIiOiJpc3YiLCJhdWQiOiJpc3YiLCJuYmYiOjE2MDQ5NzgzOTksImFwcElkIjoiMTA2NSIsInNjb3BlIjoiYXV0aF9hbGwiLCJpc3MiOiJjaGFuamV0IiwiZXhwIjoxNjA1NDk2Nzk5LCJ1c2VySWQiOiI2MTAwMDQzMjU3NSIsImlhdCI6MTYwNDk3ODM5OSwib3JnSWQiOiI5MDAwMTIwNTYyNSIsIm9yZ0FjY291bnQiOiJ1MzEzbWN2czR5d2EifQ.gPpIvM75vL39RrcNNW3jWMw28z-5nj0JNOyHjA8LvGI
"
}
}
const
manageId
=
await
this
.
getManageIdByOpenToken
(
header
);
const
manageId
=
await
getManageIdByOpenToken
(
header
);
await
this
.
postRequest
(
`
${
ydzUrl
}
/ydz/easyacctg/customer/create/{
${
manageId
}
}`
,
data
,
header
);
const
pushYDZResult
=
await
postRequest
(
`
${
ydzUrl
}
/ydz/easyacctg/customer/create/
${
manageId
}
`
,
data
,
header
);
return
pushYDZResult
;
}
}
const
getOpenTokenByAppKey
=
async
(
appKey
,
appSecret
)
=>
{
const
getOpenTokenByAppKey
=
async
(
appKey
,
appSecret
)
=>
{
const
data
=
await
this
.
postRequest
(
`
${
ydzUrl
}
/api/opreceive/accessAuth/getAppTokenByAppKey`
,
{
const
data
=
await
this
.
postRequest
(
`
${
ydzUrl
}
/api/opreceive/accessAuth/getAppTokenByAppKey`
,
{
"Content-Type"
:
"application/json"
,
"Content-Type"
:
"application/json"
,
"appKey"
:
appKey
,
"appKey"
:
appKey
,
...
@@ -31,19 +31,19 @@ const getOpenTokenByAppKey = async (appKey, appSecret) => {
...
@@ -31,19 +31,19 @@ const getOpenTokenByAppKey = async (appKey, appSecret) => {
return
data
.
token
return
data
.
token
}
}
const
getManageIdByOpenToken
=
async
(
header
)
=>
{
const
getManageIdByOpenToken
=
async
(
headers
)
=>
{
const
data
=
await
this
.
postRequest
(
`
${
centerChannelUrl
}
/ydz/setup/openAccess/MainTenant/findMainTenant`
,
{},
header
);
const
url
=
`
${
ydzUrl
}
/ydz/setup/openAccess/MainTenant/findMainTenant`
return
{
manageId
:
data
.
id
}
const
rs
=
await
getRequest
(
url
,
{},
headers
);
return
rs
.
id
;
}
}
const
postRequest
=
async
(
url
,
data
,
headers
=
{})
=>
{
const
postRequest
=
async
(
url
,
data
,
headers
=
{})
=>
{
try
{
try
{
console
.
log
(
`
${
url
}
: 请求信息 ------- `
);
console
.
log
(
`
${
url
}
: 请求信息 ------- `
);
console
.
log
(
JSON
.
stringify
(
data
))
console
.
log
(
JSON
.
stringify
(
data
))
console
.
log
(
JSON
.
stringify
(
headers
))
console
.
log
(
JSON
.
stringify
(
headers
))
let
result
=
await
axios
.
post
(
`
${
url
}
`
,
data
,
{
let
result
=
await
axios
.
post
(
`
${
url
}
`
,
data
,
{
headers
:
{
headers
:
{
'Content-Type'
:
'application/json'
,
...
headers
...
headers
}
}
});
});
...
@@ -52,18 +52,18 @@ const postRequest = async (url, data, headers = {}) => {
...
@@ -52,18 +52,18 @@ const postRequest = async (url, data, headers = {}) => {
console
.
log
(
result
);
console
.
log
(
result
);
system
.
execLogs
(
system
.
execLogs
(
`请求易代账`
,
{
`请求易代账`
,
{
url
,
url
,
data
,
data
,
headers
headers
},
},
'交付请求'
,
'交付请求'
,
result
,
result
,
null
null
).
catch
(
err
=>
{
).
catch
(
err
=>
{
console
.
log
(
`日志写入错误
${
url
}
`
)
console
.
log
(
`日志写入错误
${
url
}
`
)
});
});
if
(
result
.
status
===
0
)
{
if
(
result
.
assocTenantId
)
{
return
result
.
data
return
result
}
else
{
}
else
{
throw
new
Error
(
result
.
msg
)
throw
new
Error
(
result
.
msg
)
}
}
...
@@ -74,10 +74,26 @@ const postRequest = async (url, data, headers = {}) => {
...
@@ -74,10 +74,26 @@ const postRequest = async (url, data, headers = {}) => {
}
}
}
}
const
getRequest
=
async
(
url
,
data
,
headers
=
{})
=>
{
try
{
console
.
log
(
`
${
url
}
: 请求信息 ------- `
);
console
.
log
(
JSON
.
stringify
(
headers
));
const
res
=
await
axios
.
get
(
url
,
{
params
:
data
,
headers
:
headers
});
return
res
.
data
;
}
catch
(
err
)
{
console
.
log
(
`
${
url
}
: 返回错误信息 ------- `
);
console
.
log
(
err
)
throw
(
err
)
}
}
module
.
exports
=
{
module
.
exports
=
{
pushYiDaZhang
,
pushYiDaZhang
,
getManageIdByOpenToken
,
getManageIdByOpenToken
,
// getAppTokenByAppKey,
// getAppTokenByAppKey,
postRequest
postRequest
,
getRequest
}
}
\ No newline at end of file
icp-deliver/app/config/settings.js
View file @
9b35fe57
...
@@ -61,8 +61,8 @@ var settings = {
...
@@ -61,8 +61,8 @@ var settings = {
}
}
},
},
ydzUrl
:
function
()
{
//TODO: 易代账URL
ydzUrl
:
function
()
{
//TODO: 易代账URL
if
(
this
.
env
==
"dev"
)
{
if
(
this
.
env
==
"dev"
)
{
//集测环境
return
"https://
sandbox
-openapi.chanjet.com"
;
return
"https://
inte
-openapi.chanjet.com"
;
}
else
{
}
else
{
return
""
;
return
""
;
}
}
...
...
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