annulation de mission MAIF et DOMUS
This commit is contained in:
@@ -37,6 +37,12 @@ where d.societe = '%s' and d.no_id=%s;""" % (societe, no_id);
|
|||||||
results = request.dbsession.execute(query).first()
|
results = request.dbsession.execute(query).first()
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
def get_dossier_by_sinistre(request,societe, nosin):
|
||||||
|
query = "SELECT * FROM dem_devis WHERE societe = '%s' and nosin = '%s';" % (societe, nosin);
|
||||||
|
results = request.dbsession.execute(query).first()
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
def get_devis_by_no(request,nodossier):
|
def get_devis_by_no(request,nodossier):
|
||||||
societe = nodossier[0:2]
|
societe = nodossier[0:2]
|
||||||
type_doc = nodossier[3:5]
|
type_doc = nodossier[3:5]
|
||||||
@@ -111,6 +117,15 @@ def update_suivi(request, nodossier, nolig, new_values):
|
|||||||
|
|
||||||
execute_query(request, query, new_values)
|
execute_query(request, query, new_values)
|
||||||
|
|
||||||
|
def insert_suivi(request, nodossier, comment):
|
||||||
|
societe = nodossier[0:2]
|
||||||
|
no_id = nodossier[3:]
|
||||||
|
|
||||||
|
query = """
|
||||||
|
INSERT INTO dem_lig (societe, NO_ID, DATE, COMMENT, USERMAJ) VALUES
|
||||||
|
(:societe, :no_id, CURRENT_DATE(), :comment, 'AUTO');"""
|
||||||
|
execute_query(request, query, {'societe': societe, 'no_id': no_id, 'comment': comment})
|
||||||
|
|
||||||
def get_similaires_byChantier(request, societe, C_NOM, C_ADR, C_CP, C_VILLE):
|
def get_similaires_byChantier(request, societe, C_NOM, C_ADR, C_CP, C_VILLE):
|
||||||
|
|
||||||
query = """
|
query = """
|
||||||
@@ -258,18 +273,11 @@ def insert_facture_rdf(request, societe, nochantier, user, ref, date_rapport):
|
|||||||
query = "CALL spINS_FACTURE_RDF(:societe, :nochantier, :user, :ref, :date_rapport)"
|
query = "CALL spINS_FACTURE_RDF(:societe, :nochantier, :user, :ref, :date_rapport)"
|
||||||
execute_query(request, query, {'societe': societe, 'nochantier': nochantier, 'user': user, 'ref': ref, 'date_rapport': date_rapport})
|
execute_query(request, query, {'societe': societe, 'nochantier': nochantier, 'user': user, 'ref': ref, 'date_rapport': date_rapport})
|
||||||
|
|
||||||
def insert_dossier(request, societe, client, logged_in, c_nom, c_adr, c_adr2, c_cp, c_ville, c_tel1, nosin, c_obs, tx_trav):
|
def insert_dossier(request, societe, cd_cli, c_nom, c_adr, c_adr2, c_cp, c_ville, c_telp, nosin, c_obs, tx_trav):
|
||||||
# créer une dem_devis selon l'email de l'OS
|
# créer une dem_devis selon l'email de l'OS
|
||||||
if client == 'MAIF':
|
query = """CALL spINS_DEMANDES(:societe, :cd_cli, :c_nom, :c_adr, :c_adr2, :c_cp, :c_ville, :c_telp, 'MR', 6, :nosin, :c_obs, :tx_trav, :logged_in);"""
|
||||||
cd_cli = 2813
|
|
||||||
cabinet = 290
|
|
||||||
elif client == 'DOMUS':
|
|
||||||
cd_cli = 8991
|
|
||||||
cabinet = 289
|
|
||||||
|
|
||||||
query = """CALL spINS_DEMANDES(:societe, :cd_cli, :c_nom, :c_adr, :c_adr2, :c_cp, :c_ville, :c_tel1, 'MR', :cabinet, 6, :nosin, :c_obs, :tx_trav, :logged_in);"""
|
|
||||||
execute_query(request, query, {'societe': societe, 'cd_cli': cd_cli, 'c_nom': c_nom, 'c_adr': c_adr, 'c_adr2': c_adr2, 'c_cp': c_cp,
|
execute_query(request, query, {'societe': societe, 'cd_cli': cd_cli, 'c_nom': c_nom, 'c_adr': c_adr, 'c_adr2': c_adr2, 'c_cp': c_cp,
|
||||||
'c_ville': c_ville,'c_tel1': c_tel1, 'cabinet': cabinet, 'nosin': nosin, 'c_obs': c_obs, 'tx_trav': tx_trav, 'logged_in': logged_in})
|
'c_ville': c_ville,'c_telp': c_telp, 'nosin': nosin, 'c_obs': c_obs, 'tx_trav': tx_trav, 'logged_in': 'EMAIL'})
|
||||||
|
|
||||||
query = "SELECT no_id FROM dem_devis WHERE societe = :societe AND date = curdate() AND cd_cli = :cd_cli ORDER BY no_id desc LIMIT 1;"
|
query = "SELECT no_id FROM dem_devis WHERE societe = :societe AND date = curdate() AND cd_cli = :cd_cli ORDER BY no_id desc LIMIT 1;"
|
||||||
results = request.dbsession.execute(query, {'societe': societe, 'cd_cli': cd_cli}).first()
|
results = request.dbsession.execute(query, {'societe': societe, 'cd_cli': cd_cli}).first()
|
||||||
|
|||||||
@@ -68,7 +68,9 @@
|
|||||||
<div class="col-md-6 ${bg_color}">
|
<div class="col-md-6 ${bg_color}">
|
||||||
<table class="table table-condensed ">
|
<table class="table table-condensed ">
|
||||||
<tr>
|
<tr>
|
||||||
<td><h4>CLIENT</h4></td>
|
<td><h4>CLIENT</h4>
|
||||||
|
${dossier.CD_CLI}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<h4>${dossier.QUALITE} ${dossier.NOM}</h4>
|
<h4>${dossier.QUALITE} ${dossier.NOM}</h4>
|
||||||
${dossier.ADRESSE}<br />
|
${dossier.ADRESSE}<br />
|
||||||
|
|||||||
@@ -686,7 +686,7 @@ def demandes(request):
|
|||||||
logged_in = request.authenticated_userid.upper()
|
logged_in = request.authenticated_userid.upper()
|
||||||
url = request.route_url('demandes')
|
url = request.route_url('demandes')
|
||||||
|
|
||||||
societes = ['PE','ME','PL','PO']
|
societes = ['PE','ME','PL']
|
||||||
societe = 'PE'
|
societe = 'PE'
|
||||||
# prendre en compte les paramètres de saisie
|
# prendre en compte les paramètres de saisie
|
||||||
if 'societe' in request.params:
|
if 'societe' in request.params:
|
||||||
@@ -722,12 +722,12 @@ def demandes(request):
|
|||||||
|
|
||||||
if 'form.submitted' in request.params:
|
if 'form.submitted' in request.params:
|
||||||
# traiter les demandes de la MAIF puis de DOMUS
|
# traiter les demandes de la MAIF puis de DOMUS
|
||||||
#demandes_generer(request, conn, societe, mbx_search1, liste, logged_in)
|
# demandes_generer(request, conn, societe, mbx_search1)
|
||||||
demandes_generer(request, conn, societe, mbx_search2, liste, logged_in)
|
demandes_generer(request, conn, societe, mbx_search2)
|
||||||
|
|
||||||
liste=[]
|
liste=[]
|
||||||
# lire les demandes de la MAIF puis de DOMUS
|
# lire les demandes de la MAIF puis de DOMUS
|
||||||
demandes_afficher(conn, mbx_name, mbx_search1, liste)
|
# demandes_afficher(conn, mbx_name, mbx_search1, liste)
|
||||||
demandes_afficher(conn, mbx_name, mbx_search2, liste)
|
demandes_afficher(conn, mbx_name, mbx_search2, liste)
|
||||||
# messages lus
|
# messages lus
|
||||||
msglus = bool(liste)
|
msglus = bool(liste)
|
||||||
@@ -771,67 +771,73 @@ def demandes_afficher(conn, mbx_name, search_criteria, liste):
|
|||||||
liste.append(d)
|
liste.append(d)
|
||||||
return liste
|
return liste
|
||||||
|
|
||||||
def demandes_generer(request, conn, societe, mbx_search, liste, logged_in):
|
def demandes_generer(request, conn, societe, mbx_search):
|
||||||
|
|
||||||
def generer_dossier(request, societe, mbx_search, extracted_file, temp_file_path, logged_in):
|
def generer_mission(request, societe, mbx_search, extracted_file, temp_file_path):
|
||||||
# parcourir les lignes pour retrouver les infos utiles
|
|
||||||
with open(extracted_file) as fp:
|
|
||||||
cnt = 1
|
|
||||||
line = fp.readline()
|
|
||||||
c_obs = ''
|
|
||||||
tx_trav = ''
|
|
||||||
while line:
|
|
||||||
if line.find('Nos références') == 0:
|
|
||||||
line = fp.readline()
|
|
||||||
line = fp.readline()
|
|
||||||
no_sinistre = line[:-1]
|
|
||||||
if line.find('Bénéficiaire des travaux :') == 0:
|
|
||||||
elt = line.split(' : ')
|
|
||||||
c_nom = elt[1][:-1]
|
|
||||||
line = fp.readline()
|
|
||||||
line = fp.readline()
|
|
||||||
line = fp.readline()
|
|
||||||
c_adr = line[:-1]
|
|
||||||
line = fp.readline()
|
|
||||||
c_adr2 = line[:-1]
|
|
||||||
line = fp.readline()
|
|
||||||
c_adr3 = line[:-1]
|
|
||||||
# début 3ème ligne adr est un code postal ?
|
|
||||||
if to_int(c_adr3[0:5]) > 0 :
|
|
||||||
# oui, mémoriser le code postal et la ville
|
|
||||||
c_cp = c_adr3[0:5]
|
|
||||||
c_ville = c_adr3[6:]
|
|
||||||
else:
|
|
||||||
# non, le code postal et la ville se trouvent dans la 2è ligne
|
|
||||||
c_cp = c_adr2[0:5]
|
|
||||||
c_ville = c_adr2[6:]
|
|
||||||
c_adr2 = ''
|
|
||||||
if line.find('N° de téléphone :') == 0:
|
|
||||||
# les 10 derniers caratères
|
|
||||||
c_tel1 = line[-11:-1]
|
|
||||||
if 'une franchise de ' in line:
|
|
||||||
i1 = line.find('franchise de ')
|
|
||||||
i2 = line.find(' € ')
|
|
||||||
c_obs = line[i1:i2+2]
|
|
||||||
if ' pour un montant de ' in line:
|
|
||||||
i1 = line.find('pour un montsant de ')
|
|
||||||
tx_trav = line[i1:-2].replace(',', '.')
|
|
||||||
|
|
||||||
# lire ligne suivante
|
if 'maif.fr' in mbx_search:
|
||||||
line = fp.readline()
|
# extraire les infos de la demmande MAIF
|
||||||
cnt += 1
|
dem_info = get_pdf_infos1(extracted_file)
|
||||||
|
if societe == 'PE':
|
||||||
|
cd_cli = 2813
|
||||||
|
elif societe == 'ME':
|
||||||
|
cd_cli = 3428
|
||||||
|
else:
|
||||||
|
# VERSANIT
|
||||||
|
cd_cli = 1743
|
||||||
|
elif 'domus-services.fr' in mbx_search:
|
||||||
|
# extraire les infos de la demmande DOMUS
|
||||||
|
dem_info = get_pdf_infos2(extracted_file)
|
||||||
|
if societe == 'PE':
|
||||||
|
cd_cli = 8991
|
||||||
|
elif societe == 'ME':
|
||||||
|
cd_cli = 5276
|
||||||
|
else:
|
||||||
|
# VERSANIT
|
||||||
|
cd_cli = 3209
|
||||||
|
|
||||||
fp.close()
|
# extraction OK ? oui, créer une dem_devis et récupèrer son no_id
|
||||||
|
if dem_info['c_nom'] != '':
|
||||||
|
nochantier = insert_dossier(request, societe, cd_cli, dem_info['c_nom'], dem_info['c_adr'], dem_info['c_adr2'], \
|
||||||
|
dem_info['c_cp'], dem_info['c_ville'], dem_info['c_telp'], dem_info['no_sinistre'], dem_info['c_obs'], dem_info['tx_trav'])
|
||||||
|
nodossier = "%s-%s" % (societe, nochantier)
|
||||||
|
|
||||||
# créer une dem_devis et récupèrer son no_id
|
# récupère le nom du fichier et ajouter le no de dossier
|
||||||
nochantier = insert_dossier(request, societe, 'MAIF', logged_in, c_nom, c_adr, c_adr2, c_cp, c_ville, c_tel1, no_sinistre, c_obs, tx_trav)
|
filename = os.path.basename(temp_file_path)
|
||||||
nodossier = "%s-%s" % (societe, nochantier)
|
filename = '%s-DD%s-%s' % (societe, nochantier, filename)
|
||||||
|
tempFile2Dossier(request, societe, nochantier, '0', temp_file_path, filename, 'AUTO')
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def generer_annulation1(request, societe, extracted_file, temp_file_path):
|
||||||
|
|
||||||
|
# extraire les infos de la demmande MAIF
|
||||||
|
dem_info = get_pdf_infos1(extracted_file)
|
||||||
|
import pdb;pdb.set_trace()
|
||||||
|
# extraction OK ? oui, rechercher la dem_devis concerné
|
||||||
|
if dem_info['c_nom'] != '':
|
||||||
|
# oui, rechercher la dem_devis concerné par le no de sinistre
|
||||||
|
dem_devis = get_dossier_by_sinistre(request,societe, nosin)
|
||||||
|
nodossier = "%s-%s" % (societe, dem_devis.NO_ID)
|
||||||
|
|
||||||
|
# récupère le nom du fichier et ajouter le no de dossier
|
||||||
|
filename = '%s-DD%s-%s' % (societe, dem_devis.NO_ID, 'ANNULATION.pdf')
|
||||||
|
tempFile2Dossier(request, societe, dem_devis.NO_ID, '0', temp_file_path, filename, 'AUTO')
|
||||||
|
# insérer une ligne de suivi ANNULATION
|
||||||
|
insert_suivi(request, nodossier, '!!MISSION ANNULEE PAR la MAIF')
|
||||||
|
return
|
||||||
|
|
||||||
|
def generer_annulation2(request, societe, nosin, temp_file_path):
|
||||||
|
|
||||||
|
# oui, rechercher la dem_devis concerné par le no de sinistre
|
||||||
|
dem_devis = get_dossier_by_sinistre(request,societe, nosin)
|
||||||
|
nodossier = "%s-%s" % (societe, dem_devis.NO_ID)
|
||||||
|
|
||||||
# récupère le nom du fichier et ajouter le no de dossier
|
# récupère le nom du fichier et ajouter le no de dossier
|
||||||
filename = os.path.basename(temp_file_path)
|
filename = '%s-DD%s-%s' % (societe, dem_devis.NO_ID, 'ANNULATION.pdf')
|
||||||
filename = '%s-DD%s-%s' % (societe, nochantier, filename)
|
tempFile2Dossier(request, societe, dem_devis.NO_ID, '0', temp_file_path, filename, 'AUTO')
|
||||||
tempFile2Dossier(request, societe, nochantier, '0', temp_file, filename, logged_in)
|
# insérer une ligne de suivi ANNULATION
|
||||||
|
insert_suivi(request, nodossier, '!!MISSION ANNULEE PAR DOMUS')
|
||||||
return
|
return
|
||||||
|
|
||||||
# rechercher les emails de demandes dans le INBOX
|
# rechercher les emails de demandes dans le INBOX
|
||||||
@@ -852,21 +858,34 @@ def demandes_generer(request, conn, societe, mbx_search, liste, logged_in):
|
|||||||
raw_email_string = raw_email.decode('utf-8')
|
raw_email_string = raw_email.decode('utf-8')
|
||||||
email_message = email.message_from_string(raw_email_string)
|
email_message = email.message_from_string(raw_email_string)
|
||||||
|
|
||||||
email_subject = email_message['subject']
|
# get the message's body
|
||||||
# demande annulée ?
|
body = ''
|
||||||
if email_subject.find('Annulation ') < 0:
|
for part in email_message.walk():
|
||||||
# downloading attachment
|
ctype = part.get_content_type()
|
||||||
temp_file_path = download_pdf_to_tmp(email_message)
|
cdispo = str(part.get('Content-Disposition'))
|
||||||
|
|
||||||
# convertir le fichier pdf en texte
|
# skip any text/plain (txt) attachments
|
||||||
texte, extracted_file = pdf_convert_to_txt(temp_file_path)
|
if ctype == 'text/html' and 'attachment' not in cdispo:
|
||||||
# mission annulée
|
body = part.get_payload(decode=True) # decode
|
||||||
if 'Objet : ANNULATION MISSION' in texte:
|
break
|
||||||
# supprime le pdf
|
# downloading attachment
|
||||||
os.remove(temp_file_path)
|
temp_file_path = download_pdf_to_tmp(email_message)
|
||||||
else:
|
|
||||||
# genere le dossier d'après le mail
|
# convertir le fichier pdf en texte
|
||||||
generer_dossier(request, societe, mbx_search, extracted_file, temp_file_path, logged_in)
|
texte, extracted_file = pdf_convert_to_txt(temp_file_path)
|
||||||
|
|
||||||
|
# mission annulée ?
|
||||||
|
if 'Objet : ANNULATION MISSION' in texte :
|
||||||
|
# genere ANNULATION mission MAIF
|
||||||
|
generer_annulation1(request, societe, extracted_file, temp_file_path)
|
||||||
|
elif 'ANNULATION ORDRE DE MISSION' in texte:
|
||||||
|
import pdb;pdb.set_trace()
|
||||||
|
# genere ANNULATION mission DOMUS
|
||||||
|
nosin = str(body)[84:95]
|
||||||
|
generer_annulation2(request, societe, nosin, temp_file_path)
|
||||||
|
else:
|
||||||
|
# genere le dossier d'après le mail
|
||||||
|
generer_mission(request, societe, mbx_search, extracted_file, temp_file_path)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -988,3 +1007,132 @@ def pdf_convert_to_txt(path):
|
|||||||
|
|
||||||
return extracted_text, extracted_file
|
return extracted_text, extracted_file
|
||||||
|
|
||||||
|
def get_pdf_infos1(extracted_file):
|
||||||
|
# à partir du fichier texte du pdf
|
||||||
|
# parcourir les lignes pour retrouver les infos utiles
|
||||||
|
with open(extracted_file) as fp:
|
||||||
|
cnt = 1
|
||||||
|
line = fp.readline()
|
||||||
|
# première ligne doit être "MAIF"
|
||||||
|
if line[:-1] != 'MAIF':
|
||||||
|
return {'c_nom': ''}
|
||||||
|
|
||||||
|
c_obs = ''
|
||||||
|
tx_trav = ''
|
||||||
|
c_telp = ''
|
||||||
|
while line:
|
||||||
|
if line.find('Nos références') == 0:
|
||||||
|
line = fp.readline()
|
||||||
|
line = fp.readline()
|
||||||
|
no_sinistre = line[:-1]
|
||||||
|
if line.find('Bénéficiaire des travaux :') == 0:
|
||||||
|
elt = line.split(' : ')
|
||||||
|
c_nom = elt[1][:-1]
|
||||||
|
line = fp.readline()
|
||||||
|
line = fp.readline()
|
||||||
|
line = fp.readline()
|
||||||
|
c_adr = line[:-1]
|
||||||
|
line = fp.readline()
|
||||||
|
c_adr2 = line[:-1]
|
||||||
|
line = fp.readline()
|
||||||
|
c_adr3 = line[:-1]
|
||||||
|
# début 3ème ligne adr est un code postal ?
|
||||||
|
if to_int(c_adr3[0:5]) > 0 :
|
||||||
|
# oui, mémoriser le code postal et la ville
|
||||||
|
c_cp = c_adr3[0:5]
|
||||||
|
c_ville = c_adr3[6:]
|
||||||
|
else:
|
||||||
|
# non, le code postal et la ville se trouvent dans la 2è ligne
|
||||||
|
c_cp = c_adr2[0:5]
|
||||||
|
c_ville = c_adr2[6:]
|
||||||
|
c_adr2 = ''
|
||||||
|
if ' téléphone : ' in line:
|
||||||
|
# les 10 derniers caratères
|
||||||
|
c_tel1 = line[-11:-1]
|
||||||
|
if 'une franchise de ' in line:
|
||||||
|
i1 = line.find('franchise de ')
|
||||||
|
i2 = line.find(' € ')
|
||||||
|
c_obs = line[i1:i2+2]
|
||||||
|
if ' pour un montant de ' in line:
|
||||||
|
i1 = line.find('pour un montsant de ')
|
||||||
|
tx_trav = line[i1:-2].replace(',', '.')
|
||||||
|
|
||||||
|
# lire ligne suivante
|
||||||
|
line = fp.readline()
|
||||||
|
cnt += 1
|
||||||
|
|
||||||
|
fp.close()
|
||||||
|
return {'c_nom': c_nom,
|
||||||
|
'c_adr': c_adr,
|
||||||
|
'c_adr2': c_adr2,
|
||||||
|
'c_cp': c_cp,
|
||||||
|
'c_ville': c_ville,
|
||||||
|
'c_telp': c_telp,
|
||||||
|
'c_obs': c_obs,
|
||||||
|
'tx_trav': tx_trav,
|
||||||
|
'no_sinistre': no_sinistre,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_pdf_infos2(extracted_file):
|
||||||
|
# à partir du fichier texte du pdf de DOMUS
|
||||||
|
# parcourir les lignes pour retrouver les infos utiles
|
||||||
|
with open(extracted_file) as fp:
|
||||||
|
cnt = 1
|
||||||
|
line = fp.readline()
|
||||||
|
import pdb;pdb.set_trace()
|
||||||
|
# première ligne doit être :
|
||||||
|
if line[:-1] != 'ORDRE DE MISSION':
|
||||||
|
fp.close()
|
||||||
|
return {'c_nom': ''}
|
||||||
|
|
||||||
|
c_obs = ''
|
||||||
|
tx_trav = ''
|
||||||
|
c_telp = ''
|
||||||
|
while line:
|
||||||
|
if line.find('SINISTRE N°') == 0:
|
||||||
|
line = fp.readline()
|
||||||
|
line = fp.readline()
|
||||||
|
no_sinistre = line[:-1]
|
||||||
|
if line.find('Adresse du sinistre :') == 0:
|
||||||
|
line = fp.readline()
|
||||||
|
c_nom = line[:-1]
|
||||||
|
line = fp.readline()
|
||||||
|
c_adr = line[:-1]
|
||||||
|
line = fp.readline()
|
||||||
|
c_adr2 = line[:-1]
|
||||||
|
# début 2ème ligne adr est un code postal ?
|
||||||
|
if to_int(c_adr2) > 0 :
|
||||||
|
# oui, mémoriser le code postal et la ville
|
||||||
|
c_cp = c_adr2
|
||||||
|
line = fp.readline()
|
||||||
|
c_ville = line[:-1]
|
||||||
|
c_adr2 = ''
|
||||||
|
else:
|
||||||
|
# non, le code postal et la ville se trouvent dans la 3è ligne
|
||||||
|
line = fp.readline()
|
||||||
|
c_cp = line[:-1]
|
||||||
|
c_ville = line[:-1]
|
||||||
|
line = fp.readline()
|
||||||
|
if 'Gsm : ' in line:
|
||||||
|
# les 10 derniers caratères
|
||||||
|
c_telp = line[-11:-1]
|
||||||
|
|
||||||
|
# lire ligne suivante
|
||||||
|
line = fp.readline()
|
||||||
|
cnt += 1
|
||||||
|
|
||||||
|
fp.close()
|
||||||
|
return {'c_nom': c_nom,
|
||||||
|
'c_adr': c_adr,
|
||||||
|
'c_adr2': c_adr2,
|
||||||
|
'c_cp': c_cp[:5],
|
||||||
|
'c_ville': c_ville,
|
||||||
|
'c_telp': c_telp,
|
||||||
|
'c_obs': c_obs,
|
||||||
|
'tx_trav': tx_trav,
|
||||||
|
'no_sinistre': no_sinistre,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user