Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
third-party
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
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cooperatic-foodcoops
third-party
Commits
5b449b09
Commit
5b449b09
authored
Feb 08, 2022
by
Etienne Freiss
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Make old envelop visible
parent
d378cd28
Pipeline
#1770
failed with stage
in 1 minute 39 seconds
Changes
5
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
123 additions
and
21 deletions
+123
-21
models.py
envelops/models.py
+5
-1
envelops.js
envelops/static/js/envelops.js
+96
-18
views.py
envelops/views.py
+2
-2
couchdb.py
members/management/commands/couchdb.py
+8
-0
index.html
templates/envelops/index.html
+12
-0
No files found.
envelops/models.py
View file @
5b449b09
...
@@ -111,6 +111,10 @@ class CagetteEnvelops(models.Model):
...
@@ -111,6 +111,10 @@ class CagetteEnvelops(models.Model):
def
delete_envelop
(
self
,
envelop
):
def
delete_envelop
(
self
,
envelop
):
return
self
.
c_db
.
delete
(
envelop
)
return
self
.
c_db
.
delete
(
envelop
)
def
archive_envelop
(
self
,
envelop
):
envelop
[
'archive'
]
=
True
return
self
.
c_db
.
dbc
.
update
([
envelop
])
def
generate_envelop_display_id
(
self
):
def
generate_envelop_display_id
(
self
):
"""Generate a unique incremental id to display"""
"""Generate a unique incremental id to display"""
c_db
=
CouchDB
(
arg_db
=
'envelops'
)
c_db
=
CouchDB
(
arg_db
=
'envelops'
)
...
@@ -172,7 +176,7 @@ class CagetteEnvelops(models.Model):
...
@@ -172,7 +176,7 @@ class CagetteEnvelops(models.Model):
else
:
else
:
# Get the oldest check envelops, limited by the number of checks
# Get the oldest check envelops, limited by the number of checks
docs
=
[]
docs
=
[]
for
item
in
c_db
.
dbc
.
view
(
'index/by_type'
,
key
=
'ch'
,
include_docs
=
True
,
limit
=
payment_data
[
'checks_nb'
]):
for
item
in
c_db
.
dbc
.
view
(
'index/by_type
_not_archive
'
,
key
=
'ch'
,
include_docs
=
True
,
limit
=
payment_data
[
'checks_nb'
]):
docs
.
append
(
item
.
doc
)
docs
.
append
(
item
.
doc
)
# If only 1 check to save
# If only 1 check to save
...
...
envelops/static/js/envelops.js
View file @
5b449b09
var
cash_envelops
=
[];
var
cash_envelops
=
[];
var
archive_cash_envelops
=
[];
var
ch_envelops
=
[];
var
ch_envelops
=
[];
var
archive_ch_envelops
=
[];
var
envelop_to_update
=
null
;
var
envelop_to_update
=
null
;
function
reset
()
{
function
reset
()
{
$
(
'#cash_envelops'
).
empty
();
$
(
'#cash_envelops'
).
empty
();
$
(
'#ch_envelops'
).
empty
();
$
(
'#ch_envelops'
).
empty
();
$
(
'#archive_cash_envelops'
).
empty
();
$
(
'#archive_ch_envelops'
).
empty
();
archive_cash_envelops
=
[];
archive_ch_envelops
=
[];
cash_envelops
=
[];
cash_envelops
=
[];
ch_envelops
=
[];
ch_envelops
=
[];
}
}
...
@@ -14,7 +20,8 @@ function toggle_error_alert() {
...
@@ -14,7 +20,8 @@ function toggle_error_alert() {
}
}
function
toggle_success_alert
(
message
)
{
function
toggle_success_alert
(
message
)
{
$
(
'#envelop_cashing_success'
).
find
(
".success_alert_content"
).
text
(
message
);
$
(
'#envelop_cashing_success'
).
find
(
".success_alert_content"
)
.
text
(
message
);
$
(
'#envelop_cashing_success'
).
toggle
(
250
);
$
(
'#envelop_cashing_success'
).
toggle
(
250
);
}
}
...
@@ -65,7 +72,13 @@ function get_envelop_name(envelop, name_type = 'short') {
...
@@ -65,7 +72,13 @@ function get_envelop_name(envelop, name_type = 'short') {
* @param {Int} envelop_index
* @param {Int} envelop_index
*/
*/
function
set_envelop_dom
(
envelop
,
envelop_name
,
envelop_content_id
,
envelop_index
)
{
function
set_envelop_dom
(
envelop
,
envelop_name
,
envelop_content_id
,
envelop_index
)
{
var
envelops_section
=
$
(
'#'
+
envelop
.
type
+
'_envelops'
);
var
envelops_section
=
""
;
if
(
!
envelop
.
archive
)
envelops_section
=
$
(
'#'
+
envelop
.
type
+
'_envelops'
);
else
envelops_section
=
$
(
'#archive_'
+
envelop
.
type
+
'_envelops'
);
// Calculate envelop total amount
// Calculate envelop total amount
var
total_amount
=
0
;
var
total_amount
=
0
;
...
@@ -78,9 +91,11 @@ function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_inde
...
@@ -78,9 +91,11 @@ function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_inde
+
'<div class="flex-container">'
;
+
'<div class="flex-container">'
;
// Allow checking for all cash and first check envelops
// Allow checking for all cash and first check envelops
if
(
envelop
.
type
==
'cash'
||
envelop
.
type
==
'ch'
&&
envelop_index
==
0
)
{
if
(
(
envelop
.
type
==
'cash'
||
envelop
.
type
==
'ch'
&&
envelop_index
==
0
)
&&
!
envelop
.
archive
)
{
new_html
+=
'<button class="accordion w80">'
+
envelop_name
+
' - <i>'
+
total_amount
+
'€</i></button>'
new_html
+=
'<button class="accordion w80">'
+
envelop_name
+
' - <i>'
+
total_amount
+
'€</i></button>'
+
'<button class="btn--success archive_button item-fluid" onClick="openModal(
\'
<h3>Êtes-vous sûr ?</h3>
\'
, function() {archive_envelop(
\'
'
+
envelop
.
type
+
'
\'
, '
+
envelop_index
+
');},
\'
Encaisser
\'
, false)">Encaisser</button>'
;
+
'<button class="btn--success archive_button item-fluid" onClick="openModal(
\'
<h3>Êtes-vous sûr ?</h3>
\'
, function() {archive_envelop(
\'
'
+
envelop
.
type
+
'
\'
, '
+
envelop_index
+
');},
\'
Encaisser
\'
, false)">Encaisser</button>'
;
}
else
if
(
envelop
.
archive
&&
envelop
.
canceled
)
{
new_html
+=
'<button class="accordion w100">'
+
envelop_name
+
' - <i>'
+
total_amount
+
'€</i> (Enveloppe supprimée) </button>'
;
}
else
{
}
else
{
new_html
+=
'<button class="accordion w100">'
+
envelop_name
+
' - <i>'
+
total_amount
+
'€</i></button>'
;
new_html
+=
'<button class="accordion w100">'
+
envelop_name
+
' - <i>'
+
total_amount
+
'€</i></button>'
;
}
}
...
@@ -107,25 +122,33 @@ function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_inde
...
@@ -107,25 +122,33 @@ function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_inde
}
}
let
envelop_panel
=
$
(
`.panel_
${
envelop_content_id
}
`
);
let
envelop_panel
=
$
(
`.panel_
${
envelop_content_id
}
`
);
if
(
envelop
.
comments
)
envelop_panel
.
append
(
`<p> Commentaire :
${
envelop
.
comments
}
</p>`
);
if
(
!
envelop
.
archive
)
{
let
envelop_panel
=
$
(
`.panel_
${
envelop_content_id
}
`
);
envelop_panel
.
append
(
`<button class="btn--danger delete_envelop_button item-fluid" id="update_envelop_
${
envelop
.
type
}
_
${
envelop_index
}
">Supprimer l'enveloppe</button>`
);
envelop_panel
.
append
(
`<button class="btn--danger delete_envelop_button item-fluid" id="update_envelop_
${
envelop
.
type
}
_
${
envelop_index
}
">Supprimer l'enveloppe</button>`
);
envelop_panel
.
append
(
`<button class="btn--primary update_envelop_button item-fluid" id="update_envelop_
${
envelop
.
type
}
_
${
envelop_index
}
">Modifier</button>`
);
envelop_panel
.
append
(
`<button class="btn--primary update_envelop_button item-fluid" id="update_envelop_
${
envelop
.
type
}
_
${
envelop_index
}
">Modifier</button>`
);
$
(
".update_envelop_button"
).
off
(
"click"
);
$
(
".update_envelop_button"
).
off
(
"click"
);
$
(
".update_envelop_button"
).
on
(
"click"
,
function
()
{
$
(
".update_envelop_button"
).
on
(
"click"
,
function
()
{
let
el_id
=
$
(
this
).
attr
(
"id"
).
split
(
"_"
);
let
el_id
=
$
(
this
).
attr
(
"id"
)
.
split
(
"_"
);
envelop_to_update
=
{
envelop_to_update
=
{
type
:
el_id
[
2
],
type
:
el_id
[
2
],
index
:
el_id
[
3
],
index
:
el_id
[
3
],
lines_to_delete
:
[]
lines_to_delete
:
[]
}
};
set_update_envelop_modal
();
set_update_envelop_modal
();
});
});
$
(
".delete_envelop_button"
).
off
(
"click"
);
$
(
".delete_envelop_button"
).
off
(
"click"
);
$
(
".delete_envelop_button"
).
on
(
"click"
,
function
()
{
$
(
".delete_envelop_button"
).
on
(
"click"
,
function
()
{
let
el_id
=
$
(
this
).
attr
(
"id"
).
split
(
"_"
);
let
el_id
=
$
(
this
).
attr
(
"id"
)
.
split
(
"_"
);
let
type
=
el_id
[
2
];
let
type
=
el_id
[
2
];
let
index
=
el_id
[
3
];
let
index
=
el_id
[
3
];
let
envelop
=
get_envelop_from_type_index
(
type
,
index
);
let
envelop
=
get_envelop_from_type_index
(
type
,
index
);
...
@@ -133,12 +156,12 @@ function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_inde
...
@@ -133,12 +156,12 @@ function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_inde
openModal
(
openModal
(
"<h3>Supprimer l'enveloppe ?</h3>"
,
"<h3>Supprimer l'enveloppe ?</h3>"
,
function
()
{
function
()
{
delete
_envelop
(
envelop
);
archive_canceled
_envelop
(
envelop
);
},
},
'Supprimer'
'Supprimer'
);
);
});
});
}
}
}
/**
/**
...
@@ -148,12 +171,17 @@ function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_inde
...
@@ -148,12 +171,17 @@ function set_envelop_dom(envelop, envelop_name, envelop_content_id, envelop_inde
function
set_envelops
(
envelops
)
{
function
set_envelops
(
envelops
)
{
var
cash_index
=
0
;
var
cash_index
=
0
;
var
ch_index
=
0
;
var
ch_index
=
0
;
var
archive_cash_index
=
0
;
var
archive_ch_index
=
0
;
reset
();
reset
();
for
(
var
i
=
0
;
i
<
envelops
.
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
envelops
.
length
;
i
++
)
{
var
envelop
=
envelops
[
i
].
doc
;
var
envelop
=
envelops
[
i
].
doc
;
if
(
envelop
.
type
==
"cash"
)
{
//If the envelop is archived and more than 1 year old we delete it
if
(
envelop
.
archive
&&
(
new
Date
()
-
new
Date
(
envelop
.
creation_date
))
/
(
1000
*
3600
*
24
*
365
)
>
1
)
{
delete_envelop
(
envelop
);
}
else
if
(
envelop
.
type
==
"cash"
&&
envelop
.
archive
!=
true
)
{
cash_envelops
.
push
(
envelop
);
cash_envelops
.
push
(
envelop
);
let
envelop_name
=
get_envelop_name
(
envelop
);
let
envelop_name
=
get_envelop_name
(
envelop
);
...
@@ -162,7 +190,16 @@ function set_envelops(envelops) {
...
@@ -162,7 +190,16 @@ function set_envelops(envelops) {
set_envelop_dom
(
envelop
,
envelop_name
,
envelop_content_id
,
cash_index
);
set_envelop_dom
(
envelop
,
envelop_name
,
envelop_content_id
,
cash_index
);
cash_index
+=
1
;
cash_index
+=
1
;
}
else
if
(
envelop
.
type
==
"ch"
)
{
}
else
if
(
envelop
.
type
==
"cash"
&&
envelop
.
archive
==
true
)
{
archive_cash_envelops
.
push
(
envelop
);
let
envelop_name
=
get_envelop_name
(
envelop
);
let
envelop_content_id
=
'content_archive_cash_list_'
+
archive_cash_index
;
set_envelop_dom
(
envelop
,
envelop_name
,
envelop_content_id
,
archive_cash_index
);
archive_cash_index
+=
1
;
}
else
if
(
envelop
.
type
==
"ch"
&&
envelop
.
archive
!=
true
)
{
ch_envelops
.
push
(
envelop
);
ch_envelops
.
push
(
envelop
);
let
envelop_name
=
get_envelop_name
(
envelop
);
let
envelop_name
=
get_envelop_name
(
envelop
);
...
@@ -171,6 +208,16 @@ function set_envelops(envelops) {
...
@@ -171,6 +208,16 @@ function set_envelops(envelops) {
set_envelop_dom
(
envelop
,
envelop_name
,
envelop_content_id
,
ch_index
);
set_envelop_dom
(
envelop
,
envelop_name
,
envelop_content_id
,
ch_index
);
ch_index
+=
1
;
ch_index
+=
1
;
}
else
if
(
envelop
.
type
==
"ch"
&&
envelop
.
archive
==
true
)
{
archive_ch_envelops
.
push
(
envelop
);
let
envelop_name
=
get_envelop_name
(
envelop
);
let
envelop_content_id
=
'content_archive_ch_list_'
+
archive_ch_index
;
set_envelop_dom
(
envelop
,
envelop_name
,
envelop_content_id
,
archive_ch_index
);
archive_ch_index
+=
1
;
}
}
}
}
...
@@ -208,12 +255,14 @@ function set_update_envelop_modal() {
...
@@ -208,12 +255,14 @@ function set_update_envelop_modal() {
let
envelop_name
=
get_envelop_name
(
envelop
,
'long'
);
let
envelop_name
=
get_envelop_name
(
envelop
,
'long'
);
let
modal_update_envelop
=
$
(
'#templates #modal_update_envelop'
);
let
modal_update_envelop
=
$
(
'#templates #modal_update_envelop'
);
modal_update_envelop
.
find
(
".envelop_name"
).
text
(
envelop_name
);
modal_update_envelop
.
find
(
".envelop_name"
).
text
(
envelop_name
);
modal_update_envelop
.
find
(
".envelop_lines"
).
empty
();
modal_update_envelop
.
find
(
".envelop_lines"
).
empty
();
let
update_line_template
=
$
(
'#templates #update_envelop_line_template'
);
let
update_line_template
=
$
(
'#templates #update_envelop_line_template'
);
let
cpt
=
1
;
let
cpt
=
1
;
for
(
let
partner_id
in
envelop
.
envelop_content
)
{
for
(
let
partner_id
in
envelop
.
envelop_content
)
{
let
line
=
envelop
.
envelop_content
[
partner_id
];
let
line
=
envelop
.
envelop_content
[
partner_id
];
...
@@ -243,21 +292,26 @@ function set_update_envelop_modal() {
...
@@ -243,21 +292,26 @@ function set_update_envelop_modal() {
for
(
let
partner_id
in
envelop
.
envelop_content
)
{
for
(
let
partner_id
in
envelop
.
envelop_content
)
{
let
line
=
envelop
.
envelop_content
[
partner_id
];
let
line
=
envelop
.
envelop_content
[
partner_id
];
$
(
`#update_line_
${
partner_id
}
`
).
find
(
'.line_partner_amount'
).
val
(
line
.
amount
);
$
(
`#update_line_
${
partner_id
}
`
).
find
(
'.line_partner_amount'
)
.
val
(
line
.
amount
);
}
}
modal
.
find
(
'.envelop_comments'
).
val
((
envelop
.
comments
!==
undefined
)
?
envelop
.
comments
:
''
);
modal
.
find
(
'.envelop_comments'
).
val
((
envelop
.
comments
!==
undefined
)
?
envelop
.
comments
:
''
);
$
(
".delete_envelop_line_icon"
).
off
(
"click"
);
$
(
".delete_envelop_line_icon"
).
off
(
"click"
);
$
(
".delete_envelop_line_icon"
).
on
(
"click"
,
function
()
{
$
(
".delete_envelop_line_icon"
).
on
(
"click"
,
function
()
{
let
line_id
=
$
(
this
).
closest
(
".update_envelop_line"
).
attr
(
"id"
).
split
(
"_"
);
let
line_id
=
$
(
this
).
closest
(
".update_envelop_line"
)
.
attr
(
"id"
)
.
split
(
"_"
);
let
partner_id
=
line_id
[
line_id
.
length
-
1
];
let
partner_id
=
line_id
[
line_id
.
length
-
1
];
envelop_to_update
.
lines_to_delete
.
push
(
partner_id
);
envelop_to_update
.
lines_to_delete
.
push
(
partner_id
);
$
(
this
).
hide
();
$
(
this
).
hide
();
$
(
this
).
closest
(
".update_envelop_line"
).
find
(
".deleted_line_through"
).
show
();
$
(
this
).
closest
(
".update_envelop_line"
)
})
.
find
(
".deleted_line_through"
)
.
show
();
});
}
}
/**
/**
...
@@ -269,8 +323,11 @@ function update_envelop() {
...
@@ -269,8 +323,11 @@ function update_envelop() {
// Update lines amounts
// Update lines amounts
let
amount_inputs
=
modal
.
find
(
'.line_partner_amount'
);
let
amount_inputs
=
modal
.
find
(
'.line_partner_amount'
);
amount_inputs
.
each
(
function
(
i
,
e
)
{
let
line_id
=
$
(
e
).
closest
(
".update_envelop_line"
).
attr
(
"id"
).
split
(
"_"
);
amount_inputs
.
each
(
function
(
i
,
e
)
{
let
line_id
=
$
(
e
).
closest
(
".update_envelop_line"
)
.
attr
(
"id"
)
.
split
(
"_"
);
let
partner_id
=
line_id
[
line_id
.
length
-
1
];
let
partner_id
=
line_id
[
line_id
.
length
-
1
];
envelop
.
envelop_content
[
partner_id
].
amount
=
parseInt
(
$
(
e
).
val
());
envelop
.
envelop_content
[
partner_id
].
amount
=
parseInt
(
$
(
e
).
val
());
...
@@ -278,7 +335,7 @@ function update_envelop() {
...
@@ -278,7 +335,7 @@ function update_envelop() {
// Delete lines
// Delete lines
for
(
let
partner_id
of
envelop_to_update
.
lines_to_delete
)
{
for
(
let
partner_id
of
envelop_to_update
.
lines_to_delete
)
{
delete
(
envelop
.
envelop_content
[
partner_id
])
delete
(
envelop
.
envelop_content
[
partner_id
])
;
}
}
// Envelop comments
// Envelop comments
...
@@ -299,6 +356,28 @@ function update_envelop() {
...
@@ -299,6 +356,28 @@ function update_envelop() {
}
}
/**
/**
* archive and canceled an envelop from couchdb.
* @param {Object} envelop
*/
function
archive_canceled_envelop
(
envelop
)
{
if
(
is_time_to
(
'archive_canceled_envelop'
,
1000
))
{
envelop
.
archive
=
true
;
envelop
.
canceled
=
true
;
dbc
.
put
(
envelop
,
function
callback
(
err
,
result
)
{
if
(
!
err
&&
result
!==
undefined
)
{
toggle_deleted_alert
();
get_envelops
();
}
else
{
alert
(
"Erreur lors de la suppression de l'enveloppe... Essaye de recharger la page et réessaye."
);
console
.
log
(
err
);
}
});
}
}
/**
* Delete an envelop from couchdb.
* Delete an envelop from couchdb.
* @param {Object} envelop
* @param {Object} envelop
*/
*/
...
@@ -308,7 +387,6 @@ function delete_envelop(envelop) {
...
@@ -308,7 +387,6 @@ function delete_envelop(envelop) {
dbc
.
put
(
envelop
,
function
callback
(
err
,
result
)
{
dbc
.
put
(
envelop
,
function
callback
(
err
,
result
)
{
if
(
!
err
&&
result
!==
undefined
)
{
if
(
!
err
&&
result
!==
undefined
)
{
toggle_deleted_alert
();
get_envelops
();
get_envelops
();
}
else
{
}
else
{
alert
(
"Erreur lors de la suppression de l'enveloppe... Essaye de recharger la page et réessaye."
);
alert
(
"Erreur lors de la suppression de l'enveloppe... Essaye de recharger la page et réessaye."
);
...
...
envelops/views.py
View file @
5b449b09
...
@@ -75,8 +75,8 @@ def archive_envelop(request):
...
@@ -75,8 +75,8 @@ def archive_envelop(request):
coop_logger
.
error
(
"Cannot attach payment error message to member :
%
s"
,
str
(
e
))
coop_logger
.
error
(
"Cannot attach payment error message to member :
%
s"
,
str
(
e
))
try
:
try
:
#
Delet
e envelop from couchdb
#
archiv
e envelop from couchdb
res_envelop
=
m
.
delet
e_envelop
(
envelop
)
res_envelop
=
m
.
archiv
e_envelop
(
envelop
)
except
Exception
as
e
:
except
Exception
as
e
:
res_envelop
=
"error"
res_envelop
=
"error"
...
...
members/management/commands/couchdb.py
View file @
5b449b09
...
@@ -53,9 +53,17 @@ class Command(BaseCommand):
...
@@ -53,9 +53,17 @@ class Command(BaseCommand):
byTypeMapFunction
=
'''function(doc) {
byTypeMapFunction
=
'''function(doc) {
emit(doc.type);
emit(doc.type);
}'''
}'''
byTypeNotArchiveMapFunction
=
'''function(doc) {
if(doc.archive != true){
emit(doc.type);
}
}'''
views
=
{
views
=
{
"by_type"
:
{
"by_type"
:
{
"map"
:
byTypeMapFunction
"map"
:
byTypeMapFunction
},
"by_type_not_archive"
:
{
"map"
:
byTypeNotArchiveMapFunction
}
}
}
}
self
.
createView
(
dbConn
,
"index"
,
views
)
self
.
createView
(
dbConn
,
"index"
,
views
)
...
...
templates/envelops/index.html
View file @
5b449b09
...
@@ -39,6 +39,18 @@
...
@@ -39,6 +39,18 @@
</div>
</div>
</section>
</section>
<section
id=
"archive_cash"
>
<h2
class=
"txtcenter"
>
Enveloppes de liquide archivées
</h2>
<div
id=
"archive_cash_envelops"
class=
"flex-container flex-column-reverse"
>
</div>
</section>
<section
id=
"archive_ch"
>
<h2
class=
"txtcenter"
>
Enveloppes de chèques archivées
</h2>
<div
id=
"archive_ch_envelops"
class=
"flex-container flex-column-reverse"
>
</div>
</section>
</section>
</section>
<div
id=
"templates"
style=
"display:none;"
>
<div
id=
"templates"
style=
"display:none;"
>
...
...
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