Commit 88e08281 authored by GuanHua's avatar GuanHua
parents 6baa74d8 1e8221b6
......@@ -345,6 +345,14 @@ export const DOC_TYPE_RETURN_RECEIPT = 'S006'; // 退货入库
export const DOC_TYPE_EXCHANGE_INVOICE = 'S007'; // 换货发货单
export const DOC_TYPE_EXCHANGE_RECEIPT = 'S008'; // 换货入库单
// 单据状态
export const DOC_STATUS_UNREVIEWED = 1; // 未审核
export const DOC_STATUS_REVIEWED = 2; // 已审核
export const DOC_STATUS = {
[DOC_STATUS_UNREVIEWED]: '未审核',
[DOC_STATUS_REVIEWED]: '已审核',
};
// 订单类型
export enum OrderModalType {
......
......@@ -15,5 +15,6 @@ export const PATTERN_MAPS = {
phone: /^1[3|4|5|6|7|8|9][0-9]{9}$/,
smsCode: /^\d{6}$/,
money:/^\d*(?:\.\d{0,2})?$/,
weight:/^\d*(?:\.\d{0,3})?$/,
weight:/^\d*(?:\.\d{0,3})?$/,
quantity: /^[1-9]+[0-9]*$/, // 数量,大于等于1的正整数
}
\ No newline at end of file
......@@ -33,6 +33,6 @@ const fetchInventory = (): Promise<any[]> => {
export const createEffects = (context, actions) => {
useBusinessEffects(context, actions);
useAsyncSelect('invoicesTypeId', fetchInvoicesType, ['name', 'id']);
useAsyncSelect('invoicesTypeId', fetchInvoicesType, ['name', 'number']);
useAsyncSelect('inventoryId', fetchInventory, ['name', 'id']);
};
\ No newline at end of file
......@@ -2,7 +2,7 @@
* @Author: XieZhiXiong
* @Date: 2020-09-16 15:16:47
* @LastEditors: XieZhiXiong
* @LastEditTime: 2020-09-17 21:17:00
* @LastEditTime: 2020-09-21 11:58:49
* @Description: 联动逻辑相关
*/
import { FormEffectHooks, FormPath } from '@formily/antd';
......@@ -30,8 +30,7 @@ import Submit from '@/components/NiceForm/components/Submit';
import DateSelect from '@/components/NiceForm/components/DateSelect';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { PublicApi } from '@/services/api';
import { orderBillSchema, invoicesEnum } from '../schema';
import { a } from '@/pages/editor/configs/componentConfigs/HTML';
import { orderBillSchema } from '../schema';
const {
onFieldInputChange$,
......@@ -251,15 +250,9 @@ export const useBusinessEffects = (context, actions) => {
// 根据 单据类型 联动 对应单据所选项
onFieldValueChange$('invoicesTypeId').subscribe(fieldState => {
const origin = fieldState.originAsyncData;
const current = origin.find(item => item.id === fieldState.value);
const newEnum = [...getFieldState('relevanceInvoices', state => state.props.enum)];
if (!current) {
return;
}
switch (current.number) {
switch (fieldState.value) {
// 采购入库单、销售发货单只能选择 订单
case DOC_TYPE_PURCHASE_RECEIPT:
case DOC_TYPE_SALES_INVOICE: {
......@@ -307,11 +300,11 @@ export const useBusinessEffects = (context, actions) => {
// 对应单据改变
onFieldValueChange$('relevanceInvoices').subscribe(fieldState => {
const params = getParams(fieldState.value);
linkage.componentProps('relevanceInvoicesId', params);
linkage.componentProps('orderNo', params);
});
// 关联单据改变
onFieldValueChange$('relevanceInvoicesId').subscribe(fieldState => {
onFieldValueChange$('orderNo').subscribe(fieldState => {
const relevanceInvoicesVal = getFieldValue('relevanceInvoices');
const first = fieldState.value && fieldState.value[0];
......@@ -334,7 +327,7 @@ export const useBusinessEffects = (context, actions) => {
label: `${item.productId}/${item.productName}/¥${item.price}`,
value: item.id,
}));
setFieldState('applyMember.*.good', state => {
setFieldState('invoicesDetailsRequests.*.productName', state => {
FormPath.setIn(state, 'originAsyncData', res.data);
FormPath.setIn(state, 'props.enum', goodOptions);
});
......@@ -370,10 +363,12 @@ export const useBusinessEffects = (context, actions) => {
default:
break;
}
setFieldValue('invoicesDetailsRequests', []);
});
// 关联明细 商品下拉框 联动商品ID、单价
onFieldInputChange$('applyMember.*.good').subscribe(fieldState => {
onFieldInputChange$('invoicesDetailsRequests.*.productName').subscribe(fieldState => {
const { name, originAsyncData, value } = fieldState;
const current = originAsyncData.find(item => item.id === value);
......@@ -383,7 +378,7 @@ export const useBusinessEffects = (context, actions) => {
setFieldState(
FormPath.transform(name, /\d/, $1 => {
return `applyMember.${$1}.goodId`
return `invoicesDetailsRequests.${$1}.productId`
}),
state => {
state.value = current.productId;
......@@ -391,11 +386,58 @@ export const useBusinessEffects = (context, actions) => {
);
setFieldState(
FormPath.transform(name, /\d/, $1 => {
return `applyMember.${$1}.price`
return `invoicesDetailsRequests.${$1}.price`
}),
state => {
state.value = `¥${current.price}`;
}
);
setFieldState(
FormPath.transform(name, /\d/, $1 => {
return `invoicesDetailsRequests.${$1}.productCount`
}),
state => {
state.value = '';
}
);
setFieldState(
FormPath.transform(name, /\d/, $1 => {
return `invoicesDetailsRequests.${$1}.amount`
}),
state => {
state.value = '';
}
);
});
// 关联明细 商品数量 联动计算商品金额
onFieldInputChange$('invoicesDetailsRequests.*.productCount').subscribe(fieldState => {
const { name, value } = fieldState;
const originAsyncData = getFieldState(
FormPath.transform(name, /\d/, $1 => {
return `invoicesDetailsRequests.${$1}.productName`
}),
state => state.originAsyncData,
);
const goodId = getFieldState(
FormPath.transform(name, /\d/, $1 => {
return `invoicesDetailsRequests.${$1}.productName`
}),
state => state.value,
);;
const current = originAsyncData.find(item => item.id === goodId);
if (!current || isNaN(+value)) {
return;
}
setFieldState(
FormPath.transform(name, /\d/, $1 => {
return `invoicesDetailsRequests.${$1}.amount`
}),
state => {
state.value = `¥${(+value * current.price).toFixed(2)}`;
}
);
});
}
\ No newline at end of file
import React, { useState, useEffect, useRef } from 'react';
import { Button, Card, message } from 'antd';
import { Radio, ArrayTable } from '@formily/antd-components';
import { history } from 'umi';
import { history, Prompt } from 'umi';
import { usePageStatus } from '@/hooks/usePageStatus';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { SaveOutlined, PlusOutlined } from '@ant-design/icons';
import { createFormActions, FormEffectHooks } from '@formily/antd';
import { useRowSelectionTable } from '@/hooks/useRowSelectionTable';
import { PublicApi } from '@/services/api';
import ReutrnEle from '@/components/ReturnEle';
import NiceForm from '@/components/NiceForm';
......@@ -17,51 +16,37 @@ import Submit from '@/components/NiceForm/components/Submit';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
import { getBillsDetailSchema, goodsSearchSchema } from './schema';
import {
DEPENDENT_DOC_ORDER,
DEPENDENT_DOC_EXCHANGE,
DEPENDENT_DOC_RETURN,
DEPENDENT_DOC_PRODUCTION,
DEPENDENT_DOC_INTERNAL,
DOC_TYPE_PURCHASE_RECEIPT,
DOC_TYPE_SALES_INVOICE,
DOC_TYPE_PROCESS_RECEIPT,
DOC_TYPE_PROCESS_INVOICE,
DOC_TYPE_RETURN_INVOICE,
DOC_TYPE_RETURN_RECEIPT,
DOC_TYPE_EXCHANGE_INVOICE,
DOC_TYPE_EXCHANGE_RECEIPT,
} from '@/constants';
import { addBillSchema, goodsSearchSchema } from './schema';
import { createEffects } from './effects';
const addSchemaAction = createFormActions();
const {
onFieldValueChange$,
onFieldInputChange$,
onFormInputChange$,
} = FormEffectHooks;
const AddBills: React.FC<{}> = (props: any) => {
const { pageStatus, preview, id } = usePageStatus();
const [relevance, setRelevance] = useState(1);
const [modalColumns, setModalColumns] = useState([]);
const [visible, setVisible] = useState(false);
const [productRowSelection, productRowCtl] = useRowSelectionTable({ type: 'checkbox' });
const tableColumns = [
{ dataIndex: 'id', title: 'ID' },
{
dataIndex: 'no',
title: '货号',
render: (text, record) => <span>{text}</span>,
},
{ dataIndex: 'pname', title: '货品名称' },
{ dataIndex: 'size', title: '规格/型号' },
{ dataIndex: 'type', title: '品类' },
{ dataIndex: 'brand', title: '品牌' },
{ dataIndex: 'unit', title: '单位' },
{ dataIndex: 'name', title: '商品名称' },
{ dataIndex: 'univalence', title: '单价' },
{ dataIndex: 'numberr', title: '单据数量' },
{ dataIndex: 'price', title: '金额' },
{
dataIndex: 'ctl',
title: '操作',
render: (text, record) => (
<Button type="link" onClick={() => handleDeleteTable(record.id)}>
删除
</Button>
),
},
];
const [unsaved, setUnsaved] = useState(false);
const [infoLoading, setInfoLoading] = useState(false);
const [submitLoading, setSubmitLoading] = useState(false);
const goodsColumns: any[] = [
{
......@@ -116,18 +101,14 @@ const AddBills: React.FC<{}> = (props: any) => {
// 弹出单据明细
const handleAdd = () => {
const relevanceInvoicesIdVal = addSchemaAction.getFieldValue('relevanceInvoicesId');
console.log('relevanceInvoicesIdVal', relevanceInvoicesIdVal);
if (!relevanceInvoicesIdVal) {
const orderNoVal = addSchemaAction.getFieldValue('orderNo');
if (!orderNoVal) {
message.warning('请选择对应单据');
return;
}
setVisible(true);
};
// 删除选中单据明细
const handleDeleteTable = id => {};
const tableAddButton = (
<Button
style={{ marginBottom: 16 }}
......@@ -145,40 +126,102 @@ const AddBills: React.FC<{}> = (props: any) => {
}, []);
const handleSubmit = value => {
if (pageStatus === 0)
return PublicApi.postWarehouseInvoicesAdd({ ...value }).then(res => {
if (res.code === 1000) return history.goBack();
});
else
return PublicApi.postWarehouseInvoicesUpdata({
id: usePageStatus().id,
...value,
}).then(res => {
if (res.code === 1000) return history.goBack();
});
const { invoicesTypeId, orderNo, transactionTime, ...rest } = value;
const payload = {
orderNo: orderNo[0].id,
transactionTime: transactionTime ? transactionTime.format('YYYY-MM-DD HH:mm:ss') : '',
...rest,
};
setSubmitLoading(true);
switch (invoicesTypeId) {
// 采购入库单只能选择 订单
case DOC_TYPE_PURCHASE_RECEIPT: {
PublicApi.postOrderPurchaseReceiptAdd(payload)
.then(res => {
if (res.code !== 1000) {
return;
}
setUnsaved(false);
setTimeout(() => {
history.goBack();
}, 800);
}).finally(() => {
setSubmitLoading(false);
});
break;
}
// 销售发货单
case DOC_TYPE_SALES_INVOICE: {
break;
}
// 加工入库单
case DOC_TYPE_PROCESS_RECEIPT: {
break;
}
// 加工发货单
case DOC_TYPE_PROCESS_INVOICE: {
break;
}
// 退货发货单
case DOC_TYPE_RETURN_INVOICE: {
break;
}
// 退货入库单
case DOC_TYPE_RETURN_RECEIPT: {
break;
}
// 换货发货单
case DOC_TYPE_EXCHANGE_INVOICE: {
break;
}
// 换货入库单
case DOC_TYPE_EXCHANGE_RECEIPT: {
break;
}
default: {
break;
}
}
};
// 选择单据明细
const handleOkAddProduct = async () => {
console.log('productRowCtl.selectRow', productRowCtl.selectRow)
const values = productRowCtl.selectRow.map(item => ({
code: item.code,
name: item.name,
type: item.type,
itemNo: item.code,
itemNmae: item.name,
specifications: item.type,
category: item.customerCategory.name,
brand: item.brand.name,
unitName: item.unitName,
unit: item.unitName,
costPrice: `¥${item.costPrice}`,
good: undefined,
goodId: '',
productName: undefined,
productId: '',
price: '',
quantity: '',
productCount: '',
amount: '',
}));
addSchemaAction.setFieldValue('applyMember', values);
addSchemaAction.setFieldValue('invoicesDetailsRequests', values);
setVisible(false);
}
// 获取货品列表
const fetchProductList = async (params) => {
const res = await PublicApi.getProductGoodsGetGoodsList({
...params,
......@@ -207,6 +250,7 @@ const AddBills: React.FC<{}> = (props: any) => {
key="1"
type="primary"
icon={<SaveOutlined />}
loading={submitLoading}
onClick={() => addSchemaAction.submit()}
>
保存
......@@ -218,20 +262,23 @@ const AddBills: React.FC<{}> = (props: any) => {
<Card>
<NiceForm
expressionScope={{
tableColumns,
tableAddButton,
}}
components={{
RadioGroup: Radio.Group,
ArrayTable,
}}
effects={($, actions) => createEffects($, actions)}
effects={($, actions) => {
createEffects($, actions)
onFormInputChange$().subscribe(() => {
if (!unsaved) {
setUnsaved(true);
}
});
}}
onSubmit={handleSubmit}
actions={addSchemaAction}
schema={getBillsDetailSchema({
relevance,
modalColumns,
})}
schema={addBillSchema}
/>
</Card>
......@@ -250,7 +297,7 @@ const AddBills: React.FC<{}> = (props: any) => {
components: {
Search,
Submit,
} ,
},
effects: ($, actions) => {
useStateFilterSearchLinkageEffect(
$,
......@@ -269,6 +316,8 @@ const AddBills: React.FC<{}> = (props: any) => {
rowKey: 'id',
}}
/>
<Prompt when={unsaved} message="您还有未保存的内容,是否确定要离开?" />
</PageHeaderWrapper>
);
};
......
import React, { useState, useEffect, useRef } from 'react';
import { history } from 'umi';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Button, Card, Dropdown, Menu, Row, Col, Space, Badge } from 'antd';
import { PlusOutlined, DownOutlined, DeleteOutlined } from '@ant-design/icons';
import { Button, Card, Dropdown, Menu, Space, Badge, Popconfirm } from 'antd';
import { PlusOutlined, DownOutlined, DeleteOutlined, RollbackOutlined, SnippetsOutlined, ZoomOutOutlined } from '@ant-design/icons';
import { StandardTable } from 'god';
import { ColumnType } from 'antd/lib/table/interface';
import EyePreview from '@/components/EyePreview';
......@@ -10,24 +10,28 @@ import NiceForm from '@/components/NiceForm';
import { createFormActions, FormEffectHooks } from '@formily/antd';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { billsSchema } from './schema';
import UploadModal from '@/components/UploadModal';
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
import { PublicApi } from '@/services/api';
import { DOC_STATUS_UNREVIEWED, DOC_STATUS_REVIEWED, DOC_STATUS } from '@/constants';
import { billsSchema } from './schema';
const formActions = createFormActions();
// 模拟请求
const fetchData = async (params: any) => {
const res = await PublicApi.getWarehouseInvoicesList(params);
return res.data;
};
const Bills: React.FC<{}> = () => {
const ref = useRef<any>({});
const [selectedRowKeys, setSelectedRowKeys] = useState<Array<string>>([]);
const [selectedRowKeys, setSelectedRowKeys] = useState<Array<number>>([]);
const [visibleModal, setVisibleModal] = useState(false);
const [moreVisible, setMoreVisible] = useState(false);
const [batchLoading, setBatchLoading] = useState(false);
const fetchListData = async (params: any) => {
const res = await PublicApi.getWarehouseInvoicesList(params);
if (res.code === 1000) {
return res.data;
}
return [];
};
// 获取单据类型
const fetchInvoicesType = async () => {
......@@ -41,23 +45,129 @@ const Bills: React.FC<{}> = () => {
return data.map(v => ({ label: v.name, value: v.id }));
};
const deleteInvoices = (ids: number[], callback?: () => void) => {
setBatchLoading(true);
PublicApi.postWarehouseInvoicesBatchDelete({
ids,
}).then(res => {
if (res.code !== 1000) {
return;
}
if (callback) {
callback();
}
}).finally(() => {
setBatchLoading(false);
});
};
const auditInvoices = (ids: number[], callback?: () => void) => {
setBatchLoading(true);
PublicApi.postWarehouseInvoicesBatchReview({
ids,
}).then(res => {
if (res.code !== 1000) {
return;
}
if (callback) {
callback();
}
}).finally(() => {
setBatchLoading(false);
});
};
const counterclaimInvoices = (ids: number[], callback?: () => void) => {
setBatchLoading(true);
PublicApi.postWarehouseInvoicesBatchAgainstReview({
ids,
}).then(res => {
if (res.code !== 1000) {
return;
}
if (callback) {
callback();
}
}).finally(() => {
setBatchLoading(false);
});
};
const handleBatch = (key: React.ReactText) => {
if (!selectedRowKeys.length) {
return;
};
if (batchLoading) {
return;
}
// 这边应该需要过滤下数据,先不做,看看后台是否有过滤
switch (key) {
case 'BatchDelete': {
deleteInvoices(selectedRowKeys, () => {
setSelectedRowKeys([]);
ref.current.reload();
});
break;
}
case 'BatchAudit': {
auditInvoices(selectedRowKeys, () => {
setSelectedRowKeys([]);
ref.current.reload();
});
break;
}
case 'BatchCounterclaim': {
counterclaimInvoices(selectedRowKeys, () => {
setSelectedRowKeys([]);
ref.current.reload();
});
break;
}
default:
break;
}
};
const menu = (
<Menu onClick={e => handleBatchDel(e)}>
<Menu.Item key="1" icon={<DeleteOutlined />}>
<Menu onClick={e => handleBatch(e.key)}>
<Menu.Item key="DeleteBatch" icon={<ZoomOutOutlined />}>
删除导入批次
</Menu.Item>
<Menu.Item key="BatchDelete" icon={<DeleteOutlined />}>
批量删除
</Menu.Item>
<Menu.Item key="BatchAudit" icon={<SnippetsOutlined />}>
批量审核
</Menu.Item>
<Menu.Item key="BatchCounterclaim" icon={<RollbackOutlined />}>
批量反审
</Menu.Item>
</Menu>
);
const handleBatchDel = (e: any) => {};
const handleCounterclaim = id => {
counterclaimInvoices([id], () => {
setSelectedRowKeys([]);
ref.current.reload();
});
};
const handleMoreMenu = (e: any, record: any) => {
if (e.key != '3') {
history.push(
`/memberCenter/tranactionAbility/stockSellStorage/addBills?id=${record.id}`,
);
} else {
}
const handleAudit = id => {
auditInvoices([id], () => {
setSelectedRowKeys([]);
ref.current.reload();
});
};
const handleDelete = id => {
deleteInvoices([id], () => {
setSelectedRowKeys([]);
ref.current.reload();
});
};
const columns: ColumnType<any>[] = [
......@@ -116,41 +226,47 @@ const Bills: React.FC<{}> = () => {
dataIndex: 'state',
key: 'state',
filters: [
{ text: '未审核', value: 1 },
{ text: '已审核', value: 2 },
{ text: DOC_STATUS[DOC_STATUS_UNREVIEWED], value: DOC_STATUS_UNREVIEWED },
{ text: DOC_STATUS[DOC_STATUS_REVIEWED], value: DOC_STATUS_REVIEWED },
],
filterMultiple: false,
render: (text: any, record: any) => (
filterMultiple: false,
onFilter: (value, record) => record.state === value,
render: (text) => (
<Badge
color={record.status === 1 ? '#C1C7D0' : '#41CC9E'}
text={record.status === 1 ? '未审核' : '已审核'}
color={text === DOC_STATUS_UNREVIEWED ? '#C1C7D0' : '#41CC9E'}
text={DOC_STATUS[text]}
/>
),
},
{
title: '操作',
dataIndex: 'option',
dataIndex: 'actions',
align: 'center',
render: (text: any, record: any) => {
render: (_, record: any) => {
return (
<>
<Button type="link">审核</Button>
<Dropdown
visible={moreVisible}
overlay={
<Menu onClick={e => handleMoreMenu(e, record)}>
<Menu.Item key="1">修改</Menu.Item>
<Menu.Item key="2">反审</Menu.Item>
<Menu.Item key="3">删除</Menu.Item>
</Menu>
}
trigger={['click']}
>
<Button type="link" onClick={() => setMoreVisible(!moreVisible)}>
更多
<DownOutlined />
</Button>
</Dropdown>
{record.state === DOC_STATUS_UNREVIEWED && (
<>
<Button type="link" onClick={() => history.push(`/memberCenter/tranactionAbility/stockSellStorage/addBills?id=${record.id}`)}>修改</Button>
<Button type="link" onClick={() => handleAudit(record.id)}>审核</Button>
<Popconfirm
title="确定要删除吗?"
okText="是"
cancelText="否"
onConfirm={() => handleDelete(record.id)}
>
<Button
type="link"
danger
>
删除
</Button>
</Popconfirm>
</>
)}
{record.state === DOC_STATUS_REVIEWED && (
<Button type="link" onClick={() => handleCounterclaim(record.id)}>反审</Button>
)}
</>
);
},
......@@ -159,7 +275,9 @@ const Bills: React.FC<{}> = () => {
const rowSelection = {
selectedRowKeys: selectedRowKeys,
onChange: (selectedRowKeys: any, selectedRows: any) => {},
onChange: (selectedRowKeys: any[]) => {
setSelectedRowKeys(selectedRowKeys);
},
};
const controllerBtns = (
......@@ -194,7 +312,7 @@ const Bills: React.FC<{}> = () => {
currentRef={ref}
tableProps={{ rowKey: 'id' }}
rowSelection={rowSelection}
fetchTableData={(params: any) => fetchData(params)}
fetchTableData={(params: any) => fetchListData(params)}
controlRender={
<NiceForm
actions={formActions}
......
......@@ -25,30 +25,41 @@ const AddWarehouse: React.FC<{}> = (props: any) => {
const [submitLoading, setSubmitLoading] = useState(false);
const getWarehouseInfo = async () => {
if (!id) {
return;
}
setInfoLoading(true);
const infoRes = await PublicApi.getWarehouseWarehouseDetails({
id,
});
const areaRes = await PublicApi.getManageAreaAll();
if (areaRes.code === 1000) {
const { data } = areaRes;
formActions.setFieldState('provinceId', targetState => {
targetState.originData = data;
targetState.props.enum = data.map(v => ({
label: v.name,
value: v.id,
}));
if (id) {
setInfoLoading(true);
const infoRes = await PublicApi.getWarehouseWarehouseDetails({
id,
});
const areaRes = await PublicApi.getManageAreaAll();
if (areaRes.code === 1000) {
const { data } = areaRes;
formActions.setFieldState('provinceId', targetState => {
targetState.originData = data;
targetState.props.enum = data.map(v => ({
label: v.name,
value: v.id,
}));
});
}
if (infoRes.code === 1000) {
setInfo(infoRes.data);
}
setInfoLoading(false);
} else {
const areaRes = await PublicApi.getManageAreaAll();
if (areaRes.code === 1000) {
const { data } = areaRes;
formActions.setFieldState('provinceId', targetState => {
targetState.originData = data;
targetState.props.enum = data.map(v => ({
label: v.name,
value: v.id,
}));
});
}
}
if (infoRes.code === 1000) {
setInfo(infoRes.data);
}
setInfoLoading(false);
};
useEffect(() => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment