mirror of
https://github.com/bcomsugi/dasaproject.git
synced 2026-01-10 16:52:38 +07:00
saved
This commit is contained in:
parent
56594e963a
commit
67ab69750d
@ -9,7 +9,7 @@ import timeit
|
|||||||
import os
|
import os
|
||||||
import pythoncom
|
import pythoncom
|
||||||
# from icecream import ic
|
# from icecream import ic
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
# ic.configureOutput(includeContext=True, )
|
# ic.configureOutput(includeContext=True, )
|
||||||
class SalesOrderQuery:
|
class SalesOrderQuery:
|
||||||
@ -204,6 +204,7 @@ class SalesOrderQuery:
|
|||||||
# Memo = self.create_sub_element(ET, InvoiceAdd, "Memo", self.DN['Memo'], 10 )
|
# Memo = self.create_sub_element(ET, InvoiceAdd, "Memo", self.DN['Memo'], 10 )
|
||||||
disc_amount = 0
|
disc_amount = 0
|
||||||
for soidx, salesorder in enumerate(self.SalesOrderList):
|
for soidx, salesorder in enumerate(self.SalesOrderList):
|
||||||
|
disc_amount = 0
|
||||||
if 'TxnID' in salesorder:
|
if 'TxnID' in salesorder:
|
||||||
SOTxnId = salesorder['TxnID']
|
SOTxnId = salesorder['TxnID']
|
||||||
# disc_amount+=int(salesorder['Disc_Amount'])
|
# disc_amount+=int(salesorder['Disc_Amount'])
|
||||||
@ -254,8 +255,8 @@ class SalesOrderQuery:
|
|||||||
# print(f"replyfrom qbxml:{self.connect_to_quickbooks(qbxml_query)}")
|
# print(f"replyfrom qbxml:{self.connect_to_quickbooks(qbxml_query)}")
|
||||||
# print([s for s in qbxml_query.split('\n') if s.strip(' ') != ''])
|
# print([s for s in qbxml_query.split('\n') if s.strip(' ') != ''])
|
||||||
|
|
||||||
print(self.pprintXml(qbxml_query))
|
# print(self.pprintXml(qbxml_query))
|
||||||
return qbxml_query
|
return self.pprintXml(qbxml_query)
|
||||||
|
|
||||||
|
|
||||||
def connect_to_quickbooks(self, qbxml_query):
|
def connect_to_quickbooks(self, qbxml_query):
|
||||||
@ -306,7 +307,7 @@ class SalesOrderQuery:
|
|||||||
else:
|
else:
|
||||||
return False, status_code
|
return False, status_code
|
||||||
|
|
||||||
def get_discperpcs(self, ItemFullName, Rate:float):
|
def get_discperpcs(self, ItemFullName, Rate):
|
||||||
discPerPcs = 0
|
discPerPcs = 0
|
||||||
if self.Customer:
|
if self.Customer:
|
||||||
if self.Customer[2]:
|
if self.Customer[2]:
|
||||||
@ -321,7 +322,7 @@ class SalesOrderQuery:
|
|||||||
|
|
||||||
def _get_sales_order_header(self, response_string, includefullInvoiced=False):
|
def _get_sales_order_header(self, response_string, includefullInvoiced=False):
|
||||||
print('_get_sales_order_header')
|
print('_get_sales_order_header')
|
||||||
# print(f'responsestring:{self.pprintXml(response_string)}')
|
print(f'responsestring sales order header:{self.pprintXml(response_string)}')
|
||||||
QBXML = ET.fromstring(response_string)
|
QBXML = ET.fromstring(response_string)
|
||||||
datadict = {}
|
datadict = {}
|
||||||
SalesOrderdict = {}
|
SalesOrderdict = {}
|
||||||
@ -360,27 +361,36 @@ class SalesOrderQuery:
|
|||||||
for SalesOrderLineRet in SalesOrderLineRet:
|
for SalesOrderLineRet in SalesOrderLineRet:
|
||||||
discPerItem = 0
|
discPerItem = 0
|
||||||
discPerPcs = 0
|
discPerPcs = 0
|
||||||
|
convertQTY = 1
|
||||||
TxnLineID = SalesOrderLineRet.find('TxnLineID').text
|
TxnLineID = SalesOrderLineRet.find('TxnLineID').text
|
||||||
ItemFullName = SalesOrderLineRet.find('ItemRef/FullName')
|
ItemFullName = SalesOrderLineRet.find('ItemRef/FullName')
|
||||||
if ItemFullName is None:
|
if ItemFullName is None:
|
||||||
print("no itemfullname")
|
print("no itemfullname")
|
||||||
break
|
continue
|
||||||
else:
|
else:
|
||||||
ItemFullName=ItemFullName.text
|
ItemFullName=ItemFullName.text
|
||||||
# print(ItemFullName)
|
# print(ItemFullName)
|
||||||
Quantity = SalesOrderLineRet.find('Quantity').text
|
Quantity = SalesOrderLineRet.find('Quantity').text
|
||||||
UnitOfMeasure = SalesOrderLineRet.find('UnitOfMeasure').text
|
UnitOfMeasure = SalesOrderLineRet.find('UnitOfMeasure').text
|
||||||
|
|
||||||
|
### modified if UOM has ConvertQTY: '_' or ' of '-> in OverrideUOMSetRef
|
||||||
|
if '_' in UnitOfMeasure:
|
||||||
|
convertQTY = int(UnitOfMeasure.split('_')[1])
|
||||||
OverrideUOMSetRef = SalesOrderLineRet.find('OverrideUOMSetRef/FullName')
|
OverrideUOMSetRef = SalesOrderLineRet.find('OverrideUOMSetRef/FullName')
|
||||||
if OverrideUOMSetRef != None:
|
if OverrideUOMSetRef != None:
|
||||||
OverrideUOMSetRef = OverrideUOMSetRef.text
|
OverrideUOMSetRef = OverrideUOMSetRef.text
|
||||||
Rate = float(SalesOrderLineRet.find('Rate').text)
|
if 'of' in OverrideUOMSetRef and UnitOfMeasure.upper() == 'BOX':
|
||||||
|
convertQTY = int(OverrideUOMSetRef.split('of')[1])
|
||||||
|
print(f'OverrideUOMSetRef:{OverrideUOMSetRef}')
|
||||||
|
###
|
||||||
|
|
||||||
Amount = float(SalesOrderLineRet.find('Amount').text)
|
Rate = Decimal(SalesOrderLineRet.find('Rate').text)
|
||||||
|
Amount = Decimal(SalesOrderLineRet.find('Amount').text)
|
||||||
# if self.SPPriceLevelName:
|
# if self.SPPriceLevelName:
|
||||||
Invoiced = SalesOrderLineRet.find('Invoiced').text
|
Invoiced = SalesOrderLineRet.find('Invoiced').text
|
||||||
LineIsManuallyClosed = SalesOrderLineRet.find('IsManuallyClosed').text
|
LineIsManuallyClosed = SalesOrderLineRet.find('IsManuallyClosed').text
|
||||||
# print(TxnLineID, ItemFullName)
|
# print(TxnLineID, ItemFullName)
|
||||||
BackOrdered = float(Quantity) - float(Invoiced)
|
BackOrdered = Decimal(Quantity) - Decimal(Invoiced)
|
||||||
if BackOrdered > 0 and LineIsManuallyClosed.lower() == 'false' :
|
if BackOrdered > 0 and LineIsManuallyClosed.lower() == 'false' :
|
||||||
# ic(self.Customer)
|
# ic(self.Customer)
|
||||||
discPerPcs = self.get_discperpcs(ItemFullName, Rate)
|
discPerPcs = self.get_discperpcs(ItemFullName, Rate)
|
||||||
@ -408,6 +418,7 @@ class SalesOrderQuery:
|
|||||||
'LineIsManuallyClosed':LineIsManuallyClosed,
|
'LineIsManuallyClosed':LineIsManuallyClosed,
|
||||||
'discPerItem':discPerItem, # backorder qty * disc per pcs
|
'discPerItem':discPerItem, # backorder qty * disc per pcs
|
||||||
'discPerPcs':discPerPcs,
|
'discPerPcs':discPerPcs,
|
||||||
|
'convertQTY':convertQTY,
|
||||||
}
|
}
|
||||||
SalesOrderdict['SalesOrderLineRet'].append(SalesOrderLinedict)
|
SalesOrderdict['SalesOrderLineRet'].append(SalesOrderLinedict)
|
||||||
SalesOrderdict['Disc_Amount']=disc_amount
|
SalesOrderdict['Disc_Amount']=disc_amount
|
||||||
|
|||||||
@ -26,12 +26,8 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for so_dict in objects %}
|
{% for so_dict in objects %}
|
||||||
{{so_dict}}
|
<!-- {{so_dict}} -->
|
||||||
|
|
||||||
{{so_dict.RefNumber}}
|
|
||||||
{% for so_line in so_dict.SalesOrderLineRet %}
|
{% for so_line in so_dict.SalesOrderLineRet %}
|
||||||
{{so_dict.RefNumber}}
|
|
||||||
{{so_line.ItemFullName}}
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<input type="hidden" name="RefNumber" value="{{ so_dict.RefNumber }}">
|
<input type="hidden" name="RefNumber" value="{{ so_dict.RefNumber }}">
|
||||||
@ -43,18 +39,18 @@
|
|||||||
<input type="hidden" name="{{ k }}" value="{{ v }}">
|
<input type="hidden" name="{{ k }}" value="{{ v }}">
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input type="checkbox" name="so_field" value="{{ so_dict.TxnID }}" id="id_so_field_{{forloop.counter}}" class="form-check-input" checked>
|
<input type="checkbox" name="so_field" value="{{ so_line.TxnLineID }}" id="id_so_field_{{forloop.counter}}" class="form-check-input" checked>
|
||||||
<label for="id_so_field_{{ forloop.counter }}" class="form-check-label">{{so_line.ItemFullName}}
|
<label for="id_so_field_{{ forloop.counter }}" class="form-check-label">{{so_line.ItemFullName}}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ so_dict.TxnDate }}</td>
|
<td>{{ so_dict.TxnDate }}</td>
|
||||||
<td>{{ so_dict.RefNumber }}</td>
|
<td>{{ so_dict.RefNumber }}</td>
|
||||||
<td>{{ so_line.Quantity }}</td>
|
<td>{% widthratio so_line.Quantity so_line.convertQTY 1 %}</td>
|
||||||
<td>{{ so_line.Invoiced }}</td>
|
<td>{% widthratio so_line.Invoiced so_line.convertQTY 1 %}</td>
|
||||||
<td><input type="number" name="backordered" required value="{{ so_line.BackOrdered }}" min="0" max="{{ so_line.BackOrdered }}"> </td>
|
<td><input type="number" name="backordered" required value="{% widthratio so_line.BackOrdered so_line.convertQTY 1 %}" min="0" max="{% widthratio so_line.BackOrdered so_line.convertQTY 1 %}"> </td>
|
||||||
<td>{{ so_line.UOM }}</td>
|
<td>{{ so_line.UOM }}</td>
|
||||||
<td><input type="number" name="rate" required value="{{ so_line.Rate }}" min="0" > </td>
|
<td><input type="number" name="rate" required value="{% widthratio so_line.Rate 1 so_line.convertQTY %}" min="0" > </td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import os
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from icecream import ic
|
from icecream import ic
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
ic.configureOutput(includeContext= True)
|
ic.configureOutput(includeContext= True)
|
||||||
|
|
||||||
@ -197,21 +198,40 @@ def save_inv(request):
|
|||||||
del data['other_rate']
|
del data['other_rate']
|
||||||
print(f'others:{others}')
|
print(f'others:{others}')
|
||||||
|
|
||||||
# print(f"datadict:{data}")
|
print(f"datadict:{data}")
|
||||||
|
required_data = ['RefNumber', 'CustomerFullName', 'TxnID', 'TxnDate', 'TotalAmount', 'TxnLineID', 'ItemFullName',
|
||||||
|
'Quantity', 'UOM', 'Rate', 'Amount', 'Invoiced', 'LineIsManuallyClosed', 'backordered', 'rate', 'convertQTY']
|
||||||
|
if 'so_field' not in data:
|
||||||
|
return HttpResponse("no Selected Items. Please select at least 1 item to be invoiced.")
|
||||||
|
for _ in required_data:
|
||||||
|
if _ not in data:
|
||||||
|
return HttpResponse(f"Required data not returned from the form: {_}")
|
||||||
|
|
||||||
|
### retrieve only the selected so_field ###
|
||||||
|
so_field = data['so_field']
|
||||||
|
del data['so_field']
|
||||||
|
selectedItems = []
|
||||||
|
for _ in so_field:
|
||||||
|
if _ not in data['TxnLineID']:
|
||||||
|
return HttpResponse(f"One of the TxnLineID is not valid: {_}")
|
||||||
|
data_idx = data['TxnLineID'].index(_)
|
||||||
try:
|
try:
|
||||||
df = pd.DataFrame(data)
|
df = pd.DataFrame(data)
|
||||||
print(df)
|
print(df)
|
||||||
|
df = df[df['TxnLineID'].isin(so_field)].reset_index()
|
||||||
|
print(df)
|
||||||
except:
|
except:
|
||||||
print(Exception)
|
print(Exception)
|
||||||
return HttpResponse("DataFrame Error")
|
return HttpResponse("DataFrame Error")
|
||||||
# print(f'json:{df.to_json(orient="records")}')
|
# print(f'json:{df.to_json(orient="records")}')
|
||||||
web_dict = df.to_dict("records")
|
web_dict = df.to_dict("records")
|
||||||
# print(f'web_dict:{web_dict}' )
|
# print(f'web_dict:{web_dict}' )
|
||||||
web_dict = sorted(web_dict, key=lambda x: x['TxnLineID'])
|
web_dict = sorted(web_dict, key=lambda x: x['TxnID'])
|
||||||
# print(f'Sorted web_dict:{web_dict}' )
|
# print(f'Sorted web_dict:{web_dict}' )
|
||||||
if ('so_field' in request.POST) and ('customer_fullname' in request.POST):
|
if ('so_field' in request.POST) and ('customer_fullname' in request.POST):
|
||||||
print(request.POST.getlist('so_field'))
|
print(request.POST.getlist('so_field'))
|
||||||
open_sales_orders_TxnID = unique(request.POST.getlist('so_field'))
|
# open_sales_orders_TxnID = unique(request.POST.getlist('so_field'))
|
||||||
|
open_sales_orders_TxnID = unique(df['TxnID'].to_list())
|
||||||
customer_fullname = request.POST.get('customer_fullname')
|
customer_fullname = request.POST.get('customer_fullname')
|
||||||
print(f'Customer_fullname:{customer_fullname} -> request values:{open_sales_orders_TxnID}')
|
print(f'Customer_fullname:{customer_fullname} -> request values:{open_sales_orders_TxnID}')
|
||||||
### get the SO detail
|
### get the SO detail
|
||||||
@ -246,28 +266,34 @@ def save_inv(request):
|
|||||||
for tu_line_ret in tu_['SalesOrderLineRet']:
|
for tu_line_ret in tu_['SalesOrderLineRet']:
|
||||||
# print(tu_line_ret)
|
# print(tu_line_ret)
|
||||||
if web['TxnLineID']==tu_line_ret['TxnLineID'] and web['ItemFullName']==tu_line_ret['ItemFullName']:
|
if web['TxnLineID']==tu_line_ret['TxnLineID'] and web['ItemFullName']==tu_line_ret['ItemFullName']:
|
||||||
if 0 < float(web['backordered']) <= float(tu_line_ret['BackOrdered']):
|
### modified back the rate and backordered using convertQTY ###
|
||||||
|
convertQTY = int(tu_line_ret['convertQTY'])
|
||||||
|
webbackordered = Decimal(web['backordered']) * convertQTY
|
||||||
|
webrate = Decimal(web['rate']) / convertQTY
|
||||||
|
###
|
||||||
|
if 0 < webbackordered <= Decimal(tu_line_ret['BackOrdered']):
|
||||||
# print('put in list')
|
# print('put in list')
|
||||||
discPerPcs=0
|
discPerPcs=0
|
||||||
discPerItem=0
|
discPerItem=0
|
||||||
if float(web['rate']) == float(tu_line_ret['Rate']):
|
if webrate == Decimal(tu_line_ret['Rate']):
|
||||||
discPerPcs = ini.get_discperpcs(web['ItemFullName'], float(web['rate']))
|
discPerPcs = ini.get_discperpcs(web['ItemFullName'], webrate)
|
||||||
elif float(web['rate']) < float(tu_line_ret['Rate']):
|
elif webrate < Decimal(tu_line_ret['Rate']):
|
||||||
discPerPcs = float(tu_line_ret['Rate']) - float(web['rate'])
|
discPerPcs = Decimal(tu_line_ret['Rate']) - webrate
|
||||||
discPerItem = float(web['backordered']) * discPerPcs
|
discPerItem = webbackordered * discPerPcs
|
||||||
disc_amount += discPerItem
|
disc_amount += discPerItem
|
||||||
|
|
||||||
SalesOrderLinedict = {'TxnLineID':web['TxnLineID'],
|
SalesOrderLinedict = {'TxnLineID':web['TxnLineID'],
|
||||||
'ItemFullName':web['ItemFullName'],
|
'ItemFullName':tu_line_ret['ItemFullName'],
|
||||||
'Quantity':tu_line_ret['Quantity'],
|
'Quantity':tu_line_ret['Quantity'],
|
||||||
'UOM':tu_line_ret['UOM'],
|
'UOM':tu_line_ret['UOM'],
|
||||||
'Rate':float(web['rate']),
|
'Rate':webrate,
|
||||||
'Amount':float(tu_line_ret['Amount']),
|
'Amount':Decimal(tu_line_ret['Amount']),
|
||||||
'BackOrdered':float(web['backordered']),
|
'BackOrdered':webbackordered,
|
||||||
'Invoiced':tu_line_ret['Invoiced'],
|
'Invoiced':tu_line_ret['Invoiced'],
|
||||||
'LineIsManuallyClosed':tu_line_ret['LineIsManuallyClosed'],
|
'LineIsManuallyClosed':tu_line_ret['LineIsManuallyClosed'],
|
||||||
'discPerItem':discPerItem, # backorder qty * disc per pcs
|
'discPerItem':discPerItem, # backorder qty * disc per pcs
|
||||||
'discPerPcs':discPerPcs,
|
'discPerPcs':discPerPcs,
|
||||||
|
'convertQTY':tu_line_ret['convertQTY']
|
||||||
}
|
}
|
||||||
# print(f'salesorderlineddict:{SalesOrderLinedict}')
|
# print(f'salesorderlineddict:{SalesOrderLinedict}')
|
||||||
_salesorderlineret = dict_['SalesOrderLineRet']
|
_salesorderlineret = dict_['SalesOrderLineRet']
|
||||||
@ -277,7 +303,11 @@ def save_inv(request):
|
|||||||
break
|
break
|
||||||
break
|
break
|
||||||
print(f'last:{dict_}')
|
print(f'last:{dict_}')
|
||||||
if dict_ != data_to_save[-1]: #append the last dict_
|
print(f'datatosaveonly:{data_to_save}')
|
||||||
|
if not data_to_save:
|
||||||
|
dict_['Disc_Amount']=disc_amount
|
||||||
|
data_to_save.append(dict_)
|
||||||
|
elif dict_ != data_to_save[-1]: #append the last dict_
|
||||||
dict_['Disc_Amount']=disc_amount
|
dict_['Disc_Amount']=disc_amount
|
||||||
data_to_save.append(dict_)
|
data_to_save.append(dict_)
|
||||||
print('save the last dict')
|
print('save the last dict')
|
||||||
@ -296,9 +326,14 @@ def save_inv(request):
|
|||||||
|
|
||||||
print(invoiceaddQBXML)
|
print(invoiceaddQBXML)
|
||||||
result=None
|
result=None
|
||||||
result = ini.connect_to_quickbooks(ini.create_invoiceadd_QBXML())
|
# result = ini.connect_to_quickbooks(ini.create_invoiceadd_QBXML())
|
||||||
print("RESULT:")
|
print("RESULT:")
|
||||||
print(result)
|
print(result)
|
||||||
|
if result and ini.status_ok(result):
|
||||||
|
pass
|
||||||
|
|
||||||
|
messages.success(request, 'Invoice Has Been SAVED')
|
||||||
|
return redirect('Invoice:show_customer')
|
||||||
return render(request, "Invoice/so_details_form.html", context)
|
return render(request, "Invoice/so_details_form.html", context)
|
||||||
else:
|
else:
|
||||||
return HttpResponse(f"You cannot Save, because There Is No Open Sales Order for Customer: {customer_fullname}")
|
return HttpResponse(f"You cannot Save, because There Is No Open Sales Order for Customer: {customer_fullname}")
|
||||||
|
|||||||
@ -6,8 +6,8 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
{% comment %} <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script> {% endcomment %}
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
|
||||||
<link href= {% static 'bootstrap.min.css' %} rel="stylesheet" crossorigin="anonymous">
|
<link href= {% static 'bootstrap.min.css' %} rel="stylesheet" crossorigin="anonymous">
|
||||||
<script src= {% static 'bootstrap.bundle.min.js' %} ></script>
|
<script src= {% static 'bootstrap.bundle.min.js' %} ></script>
|
||||||
<script src="https://unpkg.com/htmx.org@1.9.6"></script>
|
<script src="https://unpkg.com/htmx.org@1.9.6"></script>
|
||||||
@ -83,6 +83,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
||||||
|
{{ message | safe }}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
{% block body %}{% endblock body %}
|
{% block body %}{% endblock body %}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user