更新登录页及优化相关功能
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import unittest
|
||||
|
||||
from sqlalchemy import CHAR, BigInteger, CheckConstraint, DateTime, Integer, String, Table, Text, UniqueConstraint
|
||||
from sqlalchemy import JSON, CHAR, BigInteger, CheckConstraint, Date, DateTime, Integer, String, Table, Text, UniqueConstraint
|
||||
from sqlalchemy.dialects import mysql
|
||||
from sqlalchemy.schema import CreateColumn, CreateTable
|
||||
|
||||
@@ -14,6 +14,7 @@ TEST_BATCH_OWNED_TABLES = {
|
||||
'biz_customer',
|
||||
'biz_customer_site',
|
||||
'biz_production_line',
|
||||
'biz_tunnel',
|
||||
'biz_warehouse',
|
||||
'biz_pallet',
|
||||
'biz_inbound_order',
|
||||
@@ -88,6 +89,20 @@ EXPECTED_COLUMNS = {
|
||||
'update_time',
|
||||
'remark',
|
||||
},
|
||||
'biz_tunnel': {
|
||||
'tunnel_id',
|
||||
'site_id',
|
||||
'tunnel_code',
|
||||
'tunnel_name',
|
||||
'current_trace_no',
|
||||
'current_trace_started_at',
|
||||
'status',
|
||||
'create_by',
|
||||
'create_time',
|
||||
'update_by',
|
||||
'update_time',
|
||||
'remark',
|
||||
},
|
||||
'biz_pallet': {
|
||||
'pallet_id',
|
||||
'pallet_code',
|
||||
@@ -133,6 +148,8 @@ EXPECTED_COLUMNS = {
|
||||
'strain_code_snapshot',
|
||||
'strain_name_snapshot',
|
||||
'batch_no',
|
||||
'production_date',
|
||||
'expiry_date',
|
||||
'package_spec',
|
||||
'initial_packages',
|
||||
'active_slot',
|
||||
@@ -178,6 +195,9 @@ EXPECTED_COLUMNS = {
|
||||
'pallet_id',
|
||||
'active_filling_id',
|
||||
'site_id',
|
||||
'tunnel_id',
|
||||
'trace_no',
|
||||
'batch_no_snapshot',
|
||||
'line_id',
|
||||
'used_packages',
|
||||
'remaining_packages_after',
|
||||
@@ -211,6 +231,9 @@ EXPECTED_COLUMNS = {
|
||||
'return_id',
|
||||
'pallet_id',
|
||||
'active_filling_id_snapshot',
|
||||
'tunnel_id_snapshot',
|
||||
'trace_no_snapshot',
|
||||
'batch_no_snapshot',
|
||||
'remaining_packages_snapshot',
|
||||
'create_by',
|
||||
'create_time',
|
||||
@@ -220,6 +243,8 @@ EXPECTED_COLUMNS = {
|
||||
'active_filling_id',
|
||||
'warehouse_id',
|
||||
'site_id',
|
||||
'tunnel_id',
|
||||
'trace_no',
|
||||
'current_line_id',
|
||||
'flow_state',
|
||||
'remaining_packages',
|
||||
@@ -238,12 +263,16 @@ EXPECTED_COLUMNS = {
|
||||
'after_state',
|
||||
'before_warehouse_id',
|
||||
'before_site_id',
|
||||
'before_tunnel_id',
|
||||
'before_line_id',
|
||||
'after_warehouse_id',
|
||||
'after_site_id',
|
||||
'after_tunnel_id',
|
||||
'after_line_id',
|
||||
'before_remaining_packages',
|
||||
'after_remaining_packages',
|
||||
'trace_no',
|
||||
'batch_no_snapshot',
|
||||
'operator_id',
|
||||
'occurred_at',
|
||||
'idempotency_key',
|
||||
@@ -263,6 +292,20 @@ EXPECTED_COLUMN_TYPES = {
|
||||
'update_time': (DateTime, None),
|
||||
'remark': (String, 500),
|
||||
},
|
||||
'biz_tunnel': {
|
||||
'tunnel_id': (BigInteger, None),
|
||||
'site_id': (BigInteger, None),
|
||||
'tunnel_code': (String, 64),
|
||||
'tunnel_name': (String, 100),
|
||||
'current_trace_no': (String, 64),
|
||||
'current_trace_started_at': (DateTime, None),
|
||||
'status': (CHAR, 1),
|
||||
'create_by': (String, 64),
|
||||
'create_time': (DateTime, None),
|
||||
'update_by': (String, 64),
|
||||
'update_time': (DateTime, None),
|
||||
'remark': (String, 500),
|
||||
},
|
||||
'biz_warehouse': {
|
||||
'warehouse_id': (BigInteger, None),
|
||||
'warehouse_code': (String, 64),
|
||||
@@ -366,6 +409,8 @@ EXPECTED_COLUMN_TYPES = {
|
||||
'strain_code_snapshot': (String, 64),
|
||||
'strain_name_snapshot': (String, 100),
|
||||
'batch_no': (String, 64),
|
||||
'production_date': (Date, None),
|
||||
'expiry_date': (Date, None),
|
||||
'package_spec': (String, 64),
|
||||
'initial_packages': (Integer, None),
|
||||
'active_slot': (String, 16),
|
||||
@@ -411,6 +456,9 @@ EXPECTED_COLUMN_TYPES = {
|
||||
'pallet_id': (BigInteger, None),
|
||||
'active_filling_id': (BigInteger, None),
|
||||
'site_id': (BigInteger, None),
|
||||
'tunnel_id': (BigInteger, None),
|
||||
'trace_no': (String, 64),
|
||||
'batch_no_snapshot': (String, 64),
|
||||
'line_id': (BigInteger, None),
|
||||
'used_packages': (Integer, None),
|
||||
'remaining_packages_after': (Integer, None),
|
||||
@@ -444,6 +492,9 @@ EXPECTED_COLUMN_TYPES = {
|
||||
'return_id': (BigInteger, None),
|
||||
'pallet_id': (BigInteger, None),
|
||||
'active_filling_id_snapshot': (BigInteger, None),
|
||||
'tunnel_id_snapshot': (BigInteger, None),
|
||||
'trace_no_snapshot': (String, 64),
|
||||
'batch_no_snapshot': (String, 64),
|
||||
'remaining_packages_snapshot': (Integer, None),
|
||||
'create_by': (String, 64),
|
||||
'create_time': (DateTime, None),
|
||||
@@ -453,6 +504,8 @@ EXPECTED_COLUMN_TYPES = {
|
||||
'active_filling_id': (BigInteger, None),
|
||||
'warehouse_id': (BigInteger, None),
|
||||
'site_id': (BigInteger, None),
|
||||
'tunnel_id': (BigInteger, None),
|
||||
'trace_no': (String, 64),
|
||||
'current_line_id': (BigInteger, None),
|
||||
'flow_state': (String, 32),
|
||||
'remaining_packages': (Integer, None),
|
||||
@@ -471,12 +524,16 @@ EXPECTED_COLUMN_TYPES = {
|
||||
'after_state': (String, 32),
|
||||
'before_warehouse_id': (BigInteger, None),
|
||||
'before_site_id': (BigInteger, None),
|
||||
'before_tunnel_id': (BigInteger, None),
|
||||
'before_line_id': (BigInteger, None),
|
||||
'after_warehouse_id': (BigInteger, None),
|
||||
'after_site_id': (BigInteger, None),
|
||||
'after_tunnel_id': (BigInteger, None),
|
||||
'after_line_id': (BigInteger, None),
|
||||
'before_remaining_packages': (Integer, None),
|
||||
'after_remaining_packages': (Integer, None),
|
||||
'trace_no': (String, 64),
|
||||
'batch_no_snapshot': (String, 64),
|
||||
'operator_id': (BigInteger, None),
|
||||
'occurred_at': (DateTime, None),
|
||||
'idempotency_key': (String, 64),
|
||||
@@ -496,6 +553,20 @@ EXPECTED_NULLABILITY = {
|
||||
'update_time': True,
|
||||
'remark': True,
|
||||
},
|
||||
'biz_tunnel': {
|
||||
'tunnel_id': False,
|
||||
'site_id': False,
|
||||
'tunnel_code': False,
|
||||
'tunnel_name': False,
|
||||
'current_trace_no': True,
|
||||
'current_trace_started_at': True,
|
||||
'status': False,
|
||||
'create_by': True,
|
||||
'create_time': True,
|
||||
'update_by': True,
|
||||
'update_time': True,
|
||||
'remark': True,
|
||||
},
|
||||
'biz_warehouse': {
|
||||
'warehouse_id': False,
|
||||
'warehouse_code': False,
|
||||
@@ -599,6 +670,8 @@ EXPECTED_NULLABILITY = {
|
||||
'strain_code_snapshot': False,
|
||||
'strain_name_snapshot': False,
|
||||
'batch_no': False,
|
||||
'production_date': True,
|
||||
'expiry_date': True,
|
||||
'package_spec': False,
|
||||
'initial_packages': False,
|
||||
'active_slot': True,
|
||||
@@ -644,7 +717,10 @@ EXPECTED_NULLABILITY = {
|
||||
'pallet_id': False,
|
||||
'active_filling_id': False,
|
||||
'site_id': False,
|
||||
'line_id': False,
|
||||
'tunnel_id': True,
|
||||
'trace_no': True,
|
||||
'batch_no_snapshot': True,
|
||||
'line_id': True,
|
||||
'used_packages': False,
|
||||
'remaining_packages_after': False,
|
||||
'idempotency_key': False,
|
||||
@@ -677,6 +753,9 @@ EXPECTED_NULLABILITY = {
|
||||
'return_id': False,
|
||||
'pallet_id': False,
|
||||
'active_filling_id_snapshot': True,
|
||||
'tunnel_id_snapshot': True,
|
||||
'trace_no_snapshot': True,
|
||||
'batch_no_snapshot': True,
|
||||
'remaining_packages_snapshot': False,
|
||||
'create_by': True,
|
||||
'create_time': True,
|
||||
@@ -686,6 +765,8 @@ EXPECTED_NULLABILITY = {
|
||||
'active_filling_id': True,
|
||||
'warehouse_id': True,
|
||||
'site_id': True,
|
||||
'tunnel_id': True,
|
||||
'trace_no': True,
|
||||
'current_line_id': True,
|
||||
'flow_state': False,
|
||||
'remaining_packages': False,
|
||||
@@ -704,12 +785,16 @@ EXPECTED_NULLABILITY = {
|
||||
'after_state': False,
|
||||
'before_warehouse_id': True,
|
||||
'before_site_id': True,
|
||||
'before_tunnel_id': True,
|
||||
'before_line_id': True,
|
||||
'after_warehouse_id': True,
|
||||
'after_site_id': True,
|
||||
'after_tunnel_id': True,
|
||||
'after_line_id': True,
|
||||
'before_remaining_packages': False,
|
||||
'after_remaining_packages': False,
|
||||
'trace_no': True,
|
||||
'batch_no_snapshot': True,
|
||||
'operator_id': False,
|
||||
'occurred_at': False,
|
||||
'idempotency_key': False,
|
||||
@@ -728,6 +813,8 @@ EXPECTED_CALLABLE_DATETIME_DEFAULTS = {
|
||||
('biz_customer_site', 'update_time'),
|
||||
('biz_production_line', 'create_time'),
|
||||
('biz_production_line', 'update_time'),
|
||||
('biz_tunnel', 'create_time'),
|
||||
('biz_tunnel', 'update_time'),
|
||||
('biz_pallet', 'create_time'),
|
||||
('biz_pallet', 'update_time'),
|
||||
('biz_user_warehouse', 'create_time'),
|
||||
@@ -757,6 +844,8 @@ EXPECTED_EMPTY_AUDIT_SERVER_DEFAULTS = {
|
||||
('biz_customer_site', 'update_by'),
|
||||
('biz_production_line', 'create_by'),
|
||||
('biz_production_line', 'update_by'),
|
||||
('biz_tunnel', 'create_by'),
|
||||
('biz_tunnel', 'update_by'),
|
||||
('biz_pallet', 'create_by'),
|
||||
('biz_pallet', 'update_by'),
|
||||
('biz_user_warehouse', 'create_by'),
|
||||
@@ -780,6 +869,7 @@ EXPECTED_PRIMARY_KEYS = {
|
||||
'biz_customer': ('customer_id',),
|
||||
'biz_customer_site': ('site_id',),
|
||||
'biz_production_line': ('line_id',),
|
||||
'biz_tunnel': ('tunnel_id',),
|
||||
'biz_pallet': ('pallet_id',),
|
||||
'biz_user_warehouse': ('user_id', 'warehouse_id'),
|
||||
'biz_user_site': ('user_id', 'site_id'),
|
||||
@@ -801,6 +891,9 @@ EXPECTED_FOREIGN_KEYS = {
|
||||
'biz_customer': set(),
|
||||
'biz_customer_site': {('customer_id', 'biz_customer.customer_id')},
|
||||
'biz_production_line': {('site_id', 'biz_customer_site.site_id')},
|
||||
'biz_tunnel': {
|
||||
('site_id', 'biz_customer_site.site_id'),
|
||||
},
|
||||
'biz_pallet': set(),
|
||||
'biz_user_warehouse': {
|
||||
('user_id', 'sys_user.user_id'),
|
||||
@@ -838,6 +931,7 @@ EXPECTED_FOREIGN_KEYS = {
|
||||
('pallet_id', 'biz_pallet.pallet_id'),
|
||||
('active_filling_id', 'biz_filling_record.filling_id'),
|
||||
('site_id', 'biz_customer_site.site_id'),
|
||||
('tunnel_id', 'biz_tunnel.tunnel_id'),
|
||||
('line_id', 'biz_production_line.line_id'),
|
||||
('operator_id', 'sys_user.user_id'),
|
||||
},
|
||||
@@ -851,12 +945,14 @@ EXPECTED_FOREIGN_KEYS = {
|
||||
('return_id', 'biz_return_order.return_id'),
|
||||
('pallet_id', 'biz_pallet.pallet_id'),
|
||||
('active_filling_id_snapshot', 'biz_filling_record.filling_id'),
|
||||
('tunnel_id_snapshot', 'biz_tunnel.tunnel_id'),
|
||||
},
|
||||
'biz_pallet_inventory': {
|
||||
('pallet_id', 'biz_pallet.pallet_id'),
|
||||
('active_filling_id', 'biz_filling_record.filling_id'),
|
||||
('warehouse_id', 'biz_warehouse.warehouse_id'),
|
||||
('site_id', 'biz_customer_site.site_id'),
|
||||
('tunnel_id', 'biz_tunnel.tunnel_id'),
|
||||
('current_line_id', 'biz_production_line.line_id'),
|
||||
('last_event_id', 'biz_pallet_event.event_id'),
|
||||
},
|
||||
@@ -864,9 +960,11 @@ EXPECTED_FOREIGN_KEYS = {
|
||||
('pallet_id', 'biz_pallet.pallet_id'),
|
||||
('before_warehouse_id', 'biz_warehouse.warehouse_id'),
|
||||
('before_site_id', 'biz_customer_site.site_id'),
|
||||
('before_tunnel_id', 'biz_tunnel.tunnel_id'),
|
||||
('before_line_id', 'biz_production_line.line_id'),
|
||||
('after_warehouse_id', 'biz_warehouse.warehouse_id'),
|
||||
('after_site_id', 'biz_customer_site.site_id'),
|
||||
('after_tunnel_id', 'biz_tunnel.tunnel_id'),
|
||||
('after_line_id', 'biz_production_line.line_id'),
|
||||
('operator_id', 'sys_user.user_id'),
|
||||
},
|
||||
@@ -878,6 +976,7 @@ EXPECTED_UNIQUE_SETS = {
|
||||
'biz_customer': {frozenset({'customer_code'})},
|
||||
'biz_customer_site': {frozenset({'customer_id', 'site_code'})},
|
||||
'biz_production_line': {frozenset({'site_id', 'line_code'})},
|
||||
'biz_tunnel': {frozenset({'site_id', 'tunnel_code'})},
|
||||
'biz_pallet': {frozenset({'pallet_code'}), frozenset({'qr_token'})},
|
||||
'biz_user_warehouse': set(),
|
||||
'biz_user_site': set(),
|
||||
@@ -913,6 +1012,36 @@ EXPECTED_UNIQUE_SETS = {
|
||||
},
|
||||
}
|
||||
|
||||
# 收货补齐:与既有日期、隧道契约并存,不用当前时间填充历史收货记录。
|
||||
EXPECTED_COLUMNS['biz_shipment_order'].update({
|
||||
'receipt_state', 'received_by', 'received_at', 'receipt_idempotency_key', 'receipt_request_hash',
|
||||
})
|
||||
EXPECTED_COLUMN_TYPES['biz_shipment_order'].update({
|
||||
'receipt_state': (String, 16),
|
||||
'received_by': (BigInteger, None),
|
||||
'received_at': (DateTime, None),
|
||||
'receipt_idempotency_key': (String, 64),
|
||||
'receipt_request_hash': (String, 64),
|
||||
})
|
||||
EXPECTED_NULLABILITY['biz_shipment_order'].update({
|
||||
'receipt_state': False,
|
||||
'received_by': True,
|
||||
'received_at': True,
|
||||
'receipt_idempotency_key': True,
|
||||
'receipt_request_hash': True,
|
||||
})
|
||||
EXPECTED_FOREIGN_KEYS['biz_shipment_order'].add(('received_by', 'sys_user.user_id'))
|
||||
EXPECTED_UNIQUE_SETS['biz_shipment_order'].add(frozenset({'target_site_id', 'receipt_idempotency_key'}))
|
||||
EXPECTED_COLUMNS['biz_pallet_inventory'].add('site_arrived_at')
|
||||
EXPECTED_COLUMN_TYPES['biz_pallet_inventory']['site_arrived_at'] = (DateTime, None)
|
||||
EXPECTED_NULLABILITY['biz_pallet_inventory']['site_arrived_at'] = True
|
||||
|
||||
for fifo_table in ('biz_usage_record', 'biz_pallet_event'):
|
||||
EXPECTED_COLUMNS[fifo_table].update({'fifo_skip_reason', 'fifo_recommendation'})
|
||||
EXPECTED_NULLABILITY[fifo_table].update({'fifo_skip_reason': True, 'fifo_recommendation': True})
|
||||
EXPECTED_COLUMN_TYPES[fifo_table]['fifo_skip_reason'] = (String, 500)
|
||||
EXPECTED_COLUMN_TYPES[fifo_table]['fifo_recommendation'] = (JSON, None)
|
||||
|
||||
for table_name in TEST_BATCH_OWNED_TABLES:
|
||||
EXPECTED_COLUMNS[table_name].add('test_batch_id')
|
||||
EXPECTED_COLUMN_TYPES[table_name]['test_batch_id'] = (BigInteger, None)
|
||||
@@ -1064,7 +1193,7 @@ class BusinessModelContractTest(unittest.TestCase):
|
||||
def test_batch_related_tables_compile_for_mysql(self) -> None:
|
||||
self.assertIs(Base.metadata.tables['sys_user'], user_do.SysUser.__table__)
|
||||
batch_tables = EXPECTED_TEST_BATCH_TABLES | TEST_BATCH_OWNED_TABLES
|
||||
self.assertEqual(18, len(batch_tables))
|
||||
self.assertEqual(19, len(batch_tables))
|
||||
for table_name in batch_tables:
|
||||
for dialect_name, dialect in (('mysql', mysql.dialect()),):
|
||||
with self.subTest(table_name=table_name, dialect=dialect_name):
|
||||
@@ -1078,6 +1207,7 @@ class BusinessModelContractTest(unittest.TestCase):
|
||||
'biz_customer',
|
||||
'biz_customer_site',
|
||||
'biz_production_line',
|
||||
'biz_tunnel',
|
||||
'biz_pallet',
|
||||
'biz_user_warehouse',
|
||||
'biz_user_site',
|
||||
@@ -1102,6 +1232,7 @@ class BusinessModelContractTest(unittest.TestCase):
|
||||
master_do.BizCustomer: 'biz_customer',
|
||||
master_do.BizCustomerSite: 'biz_customer_site',
|
||||
master_do.BizProductionLine: 'biz_production_line',
|
||||
master_do.BizTunnel: 'biz_tunnel',
|
||||
master_do.BizPallet: 'biz_pallet',
|
||||
master_do.BizUserWarehouse: 'biz_user_warehouse',
|
||||
master_do.BizUserSite: 'biz_user_site',
|
||||
@@ -1258,6 +1389,7 @@ class BusinessModelContractTest(unittest.TestCase):
|
||||
'biz_customer': {'ck_biz_customer_status': "statusIN('0','1')"},
|
||||
'biz_customer_site': {'ck_biz_customer_site_status': "statusIN('0','1')"},
|
||||
'biz_production_line': {'ck_biz_production_line_status': "statusIN('0','1')"},
|
||||
'biz_tunnel': {'ck_biz_tunnel_status': "statusIN('0','1')"},
|
||||
'biz_pallet': {
|
||||
'ck_biz_pallet_capacity_packages': 'capacity_packages>0',
|
||||
'ck_biz_pallet_asset_status': "asset_statusIN('0','1')",
|
||||
@@ -1267,10 +1399,12 @@ class BusinessModelContractTest(unittest.TestCase):
|
||||
},
|
||||
'biz_filling_record': {
|
||||
'ck_biz_filling_record_initial_packages': 'initial_packages>0',
|
||||
'ck_biz_filling_record_material_dates': '(production_dateISNULLANDexpiry_dateISNULL)OR(production_dateISNOTNULLANDexpiry_dateISNOTNULLANDexpiry_date>=production_date)',
|
||||
'ck_biz_filling_record_active_slot': "active_slotISNULLORactive_slot='ACTIVE'",
|
||||
},
|
||||
'biz_shipment_order': {
|
||||
'ck_biz_shipment_order_status': "statusIN('DRAFT','CONFIRMED')",
|
||||
'ck_biz_shipment_order_receipt_state': "receipt_stateIN('PENDING','RECEIVED','LEGACY')",
|
||||
},
|
||||
'biz_shipment_item': {
|
||||
'ck_biz_shipment_item_package_qty': 'package_qtyISNULLORpackage_qty>0',
|
||||
@@ -1288,7 +1422,7 @@ class BusinessModelContractTest(unittest.TestCase):
|
||||
'biz_pallet_inventory': {
|
||||
'ck_biz_pallet_inventory_flow_state': (
|
||||
"flow_stateIN('UNSTOCKED','EMPTY_IN_WAREHOUSE','FILLED_IN_WAREHOUSE',"
|
||||
"'AT_SITE_UNUSED','AT_SITE_PARTIAL','AT_SITE_EMPTY','RETURNING')"
|
||||
"'IN_TRANSIT','AT_SITE_UNUSED','AT_SITE_PARTIAL','AT_SITE_EMPTY','RETURNING')"
|
||||
),
|
||||
'ck_biz_pallet_inventory_remaining_packages': 'remaining_packages>=0',
|
||||
'ck_biz_pallet_inventory_version': 'version>=0',
|
||||
@@ -1296,7 +1430,7 @@ class BusinessModelContractTest(unittest.TestCase):
|
||||
},
|
||||
'biz_pallet_event': {
|
||||
'ck_biz_pallet_event_event_type': (
|
||||
"event_typeIN('INBOUND_CONFIRMED','FILLING_CONFIRMED','SHIPMENT_CONFIRMED',"
|
||||
"event_typeIN('INBOUND_CONFIRMED','FILLING_CONFIRMED','SHIPMENT_CONFIRMED','SHIPMENT_RECEIVED','TUNNEL_ENTERED',"
|
||||
"'USAGE_RECORDED','RETURN_REQUESTED','RETURN_CONFIRMED')"
|
||||
),
|
||||
},
|
||||
@@ -1312,6 +1446,7 @@ class BusinessModelContractTest(unittest.TestCase):
|
||||
'biz_customer': 'status',
|
||||
'biz_customer_site': 'status',
|
||||
'biz_production_line': 'status',
|
||||
'biz_tunnel': 'status',
|
||||
'biz_pallet': 'asset_status',
|
||||
}
|
||||
for table_name, column_name in char_statuses.items():
|
||||
@@ -1375,15 +1510,19 @@ class BusinessModelContractTest(unittest.TestCase):
|
||||
'active_filling_id',
|
||||
'warehouse_id',
|
||||
'site_id',
|
||||
'tunnel_id',
|
||||
'trace_no',
|
||||
'current_line_id',
|
||||
'last_event_id',
|
||||
},
|
||||
'biz_pallet_event': {
|
||||
'before_warehouse_id',
|
||||
'before_site_id',
|
||||
'before_tunnel_id',
|
||||
'before_line_id',
|
||||
'after_warehouse_id',
|
||||
'after_site_id',
|
||||
'after_tunnel_id',
|
||||
'after_line_id',
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user