Commit fc3c74ad authored by GuanHua's avatar GuanHua

feat: 发票功能开发

parent b2cc6298
......@@ -603,18 +603,28 @@ const BalancedRoute = {
"component": "@/pages/balance/invoice/srm/inquire",
"relationParentCode": "balance",
"name": "发票查询",
// "hideInMenu": true,
"icon": "smile",
"btns": []
},
{
"path": "/memberCenter/balance/invoice/detail",
"component": "@/pages/balance/invoice/srm/invoiceDetail",
"component": "@/pages/balance/invoice/srm/manage/detail",
"relationParentCode": "balance",
"hideInMenu": true,
"noMargin": true,
"name": "发票详情",
"icon": "smile",
"btns": []
},
{
"path": "/memberCenter/balance/invoice/edit",
"component": "@/pages/balance/invoice/srm/manage/edit",
"relationParentCode": "balance",
"hideInMenu": true,
"noMargin": true,
"name": "编辑发票",
"icon": "smile",
"btns": []
}
]
},
......@@ -634,9 +644,10 @@ const BalancedRoute = {
},
{
"path": "/memberCenter/balance/invoiceJoint/detail",
"component": "@/pages/balance/invoice/srm/invoiceDetail",
"component": "@/pages/balance/invoice/srm/manage/detail",
"relationParentCode": "balance",
"hideInMenu": true,
"noMargin": true,
"name": "发票详情",
"icon": "smile",
"btns": []
......
......@@ -9,6 +9,10 @@ import { FormDetailContext } from '@/formSchema/context'
const { Link } = Anchor;
const intl = getIntl();
export interface FormDetailHeaderProps {
/**
* 是否显示信息完成度
*/
showProcess?: boolean,
title: string,
/**
* 右侧额外操作
......@@ -35,6 +39,7 @@ interface itemProps extends ISchema {
*/
const FormDetailHeader: React.FC<FormDetailHeaderProps> = ({
showProcess,
title,
extraRight,
backLink,
......@@ -95,9 +100,13 @@ const FormDetailHeader: React.FC<FormDetailHeaderProps> = ({
<Col>
<div className={style.titleAvatorText}>{title}</div>
</Col>
<Col>
<div className={style.titleCompleteProcess}>{intl.formatMessage({id: 'components.xinxiwanchengdu'})}{` ${parseInt((Number(ctx.formContext.formProcess || 0) * 100).toFixed(2))}%`}</div>
</Col>
{
showProcess && (
<Col>
<div className={style.titleCompleteProcess}>{intl.formatMessage({id: 'components.xinxiwanchengdu'})}{` ${parseInt((Number(ctx.formContext.formProcess || 0) * 100).toFixed(2))}%`}</div>
</Col>
)
}
</Row>
<Row>
<Col>
......@@ -131,6 +140,8 @@ const FormDetailHeader: React.FC<FormDetailHeaderProps> = ({
)
}
FormDetailHeader.defaultProps = {}
FormDetailHeader.defaultProps = {
showProcess: true,
}
export default FormDetailHeader
.god-standard-table {
position: relative;
height: 100%;
}
.god-table-control {
margin-bottom: 24px;
}
\ No newline at end of file
}
......@@ -59,7 +59,7 @@ interface Iprops {
*/
rowSelection?: {
getCheckboxProps?: (record) => any,
}
},
}
const TableModal: React.FC<Iprops> = (props: Iprops) => {
......@@ -210,10 +210,10 @@ const TableModal: React.FC<Iprops> = (props: Iprops) => {
// <div>{child}</div>
// <div>{ps}</div>
// </div>
<div style={{position: "relative", }}>
<>
<div >{child}</div>
<div style={{position: 'absolute', right: 0, top: 4}}>{ps}</div>
</div>
<div style={{position: 'absolute', right: 0, bottom: 4}}>{ps}</div>
</>
)}
controlRender={
<NiceForm
......
......@@ -136,11 +136,13 @@ const UploadFiles: React.FC<PickUploadProps> = (props: PickUploadProps) => {
const getIconByName = (name: string) => {
if (name && typeof name === 'string') {
const tempList = name.split('.')
const fileType = tempList[tempList.length - 1]
if (fileType.indexOf('pdf') > -1) {
const fileType = tempList[tempList.length - 1].toLocaleUpperCase()
if (fileType.indexOf('PDF') > -1) {
return pdfIcon
} else {
} else if (['JPG', 'PNG', 'GIF', 'JPEG'].includes(fileType)) {
return photoIcon
} else {
return othersIcon
}
}
return othersIcon
......
import React from 'react'
import UploadFiles from '@/components/UploadFiles/UploadFiles'
import styles from './index.less'
import pdfIcon from '@/assets/imgs/pdf_icon.png';
import photoIcon from '@/assets/imgs/file_photo.png'
import othersIcon from '@/assets/imgs/file_others.png'
import { UploadFile, UploadChangeParam } from 'antd/lib/upload/interface'
import { DeleteOutlined } from '@ant-design/icons'
import styles from './index.less'
interface UploadInvoiceProps {
path: string
......@@ -10,56 +14,91 @@ interface UploadInvoiceProps {
props: {
readOnly: boolean
},
editable: boolean,
mutators: {
change: (params: any) => void
},
}
const UploadInvoice:React.FC<UploadInvoiceProps> & { isFieldComponent: boolean } = (props) => {
const { value, mutators } = props
const { value = [], mutators, editable } = props
const handleFilesChange = (info: UploadChangeParam) => {
if (info) {
const fileList = info.fileList;
const urlLIst = fileList.map((file) => file.url)
console.log(urlLIst, 'urlLIst')
mutators.change([...urlLIst])
const urlList = fileList.map((file) => file.response?.data).filter((item) => item !== undefined)
mutators.change([...urlList, ...value, ])
}
}
const handleDeleteItem = (imgUrl: string) => {
const newList = value.filter((url) => url !== imgUrl)
mutators.change([...newList])
}
const handleFileRemove = (fileItem: UploadFile) => {
if (value && fileItem.url) {
const filterUrlList = value.filter((imgUrl) => imgUrl !== fileItem.url)
console.log(filterUrlList, 'filterUrlList')
mutators.change([...filterUrlList])
}
}
const getIconByName = (name: string) => {
if (name && typeof name === 'string') {
const tempList = name.split('.')
const fileType = tempList[tempList.length - 1].toLocaleUpperCase()
if (fileType.indexOf('PDF') > -1) {
return pdfIcon
} else if (['JPG', 'PNG', 'GIF', 'JPEG'].includes(fileType)) {
return photoIcon
} else {
return othersIcon
}
}
return othersIcon
}
const formatImgUrl = (url: string): string => {
return (url && typeof url === 'string') ? url.slice(-25) : ''
}
return (
<div className={styles.upload_invoice}>
{/* {
{
(value && value.length > 0) && (
<div className={styles.upload_file_list}>
{
value.map((item) => (
<div className={styles.upload_file_list_item}>
value.map((item, index) => (
<div className={styles.upload_file_list_item} key={`img_item_${index}`}>
<img className={styles.file_type_icon} src={getIconByName(item)} />
<span className={styles.file_name}>{item}</span>
<a
className={styles.file_name}
href={item}
target="_blank"
title={item} rel="noreferrer"
>
{formatImgUrl(item)}
</a>
{
!props.props.readOnly && <DeleteOutlined onClick={() => handleDeleteItem(item)} className={styles.delete_btn} />
editable && <DeleteOutlined onClick={() => handleDeleteItem(item)} className={styles.delete_btn} />
}
</div>
))
}
</div>
)
} */}
<UploadFiles
btnClassName={styles.upload_btn}
buttonText='上传'
onChange={handleFilesChange}
onRemove={handleFileRemove}
/>
}
{
editable && (
<UploadFiles
btnClassName={styles.upload_btn}
showFiles={false}
buttonText='上传'
onChange={handleFilesChange}
onRemove={handleFileRemove}
/>
)
}
</div>
)
}
......
......@@ -63,7 +63,7 @@ export const ProductTableCell:React.FC<ProductTableCellProps> = ({
switch(type) {
case 'number': {
return <Input
style={{ width: 100 }}
style={{ width: 60 }}
type='number'
ref={formItemRef}
onChange={save}
......@@ -80,6 +80,7 @@ export const ProductTableCell:React.FC<ProductTableCellProps> = ({
childNode =
<Form.Item
className="customFormItem"
style={{ marginBottom: 0 }}
name={dataIndex}
initialValue={record[dataIndex] || ''}
rules={[
......@@ -90,7 +91,7 @@ export const ProductTableCell:React.FC<ProductTableCellProps> = ({
{
pattern: PATTERN_MAPS.decimal,
message: `${title}${intl.formatMessage({ id: 'balance.invoice.quantity.decimal.max', defaultMessage: '最多3位小数' })}`,
}
},
]}
>
{chooseFormItem(formItem)}
......
/**
* 开票查询(SRM)
*/
import React, { useRef, useState } from 'react';
import { getIntl, useIntl, Link } from 'umi';
import React, { useEffect, useRef, useState } from 'react';
import { getIntl, useIntl, history } from 'umi';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Card, Button, DatePicker, Space, Badge, Drawer, message } from 'antd';
import NiceForm from '@/components/NiceForm';
......@@ -22,6 +22,8 @@ import {
} from '@/services/SettleV2Api';
import AuthButton from '@/components/AuthButton';
import './index.less';
import moment from 'moment';
import { usePageStatus } from '@/hooks/usePageStatus';
const intl = getIntl();
const RangePicker = DatePicker.RangePicker;
......@@ -30,7 +32,8 @@ const formActions = createFormActions();
const InvoiceInquire: React.FC = () => {
const intl = useIntl();
const ref = useRef<any>({});
const { searchData, formatInitialValue } = useSetSearchValueInTable();
const { reconciliationNo } = usePageStatus()
const DATE_FORMAT = 'YYYY-MM-DD HH:mm:ss'
/**
* @param params
......@@ -38,9 +41,12 @@ const InvoiceInquire: React.FC = () => {
const fetchListData = async params => {
const searchParams = {
...params,
...searchData,
orderByCode: 1,
};
if (reconciliationNo) {
searchParams.reconciliationNo = reconciliationNo
}
const { data } = await getSettleAccountsMemberSettlementAccountStatementInvoiceList(
searchParams,
);
......@@ -51,30 +57,13 @@ const InvoiceInquire: React.FC = () => {
* 搜索
*/
const handleSearch = values => {
const format = 'YYYY-MM-DD';
const payStartTime = values.payStartTime?.format(format);
const payEndTime = values.payEndTime
? values.payEndTime.endOf('day').format('YYYY-MM-DD HH:mm:ss')
: '';
const orderStartTime = values.orderStartTime?.format(format);
const orderEndTime = values.orderEndTime
? values.orderEndTime.endOf('day').format('YYYY-MM-DD HH:mm:ss')
: '';
ref.current.reload({
...values,
payStartTime,
payEndTime,
orderStartTime,
orderEndTime,
invoiceStartDate: values?.invoiceStartDate ? values?.invoiceStartDate.format(DATE_FORMAT) : undefined,
invoiceEndDate: values?.invoiceEndDate ? values?.invoiceEndDate.format(DATE_FORMAT) : undefined,
});
};
const _handleOrderNo = record => {
window.open(
`/memberCenter/balance/businessReconciliation/search/preview?id=${record.reconciliationId}&no=${record.reconciliationNo}`,
);
};
const columns = [
{
title: intl.formatMessage({
......@@ -85,7 +74,7 @@ const InvoiceInquire: React.FC = () => {
<Button
type="link"
onClick={() => {
_handleOrderNo(record);
history.push(`/memberCenter/balance/invoice/detail?reconciliationId=${record.reconciliationId}&id=${record.id}`)
}}
>
{text}
......@@ -134,6 +123,7 @@ const InvoiceInquire: React.FC = () => {
id: 'balance.accountsReceivable.invoice.columns.invoiceDate',
}),
dataIndex: 'invoiceDate',
render: date => moment(date).format('YYYY-MM-DD')
},
{
title: intl.formatMessage({
......@@ -190,22 +180,6 @@ const InvoiceInquire: React.FC = () => {
);
},
},
{
title: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.operation',
}),
render: (_, record) => {
return (
<Link
to={`/memberCenter/balance/invoice/detail?id=${record.reconciliationId}`}
>
{intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.operation.1',
})}
</Link>
);
},
},
];
return (
......@@ -223,6 +197,7 @@ const InvoiceInquire: React.FC = () => {
components={{
RangePicker,
}}
initialValues={{}}
actions={formActions}
effects={($, actions) => {
useStateFilterSearchLinkageEffect(
......@@ -238,13 +213,6 @@ const InvoiceInquire: React.FC = () => {
}}
schema={schema}
onSubmit={handleSearch}
onReset={() => {
formActions.setFieldValue('payStartTime', null);
formActions.setFieldValue('payEndTime', null);
formActions.setFieldValue('orderStartTime', null);
formActions.setFieldValue('orderEndTime', null);
}}
{...formatInitialValue}
/>
}
/>
......
......@@ -48,7 +48,7 @@ export const schema: ISchema = {
allowClear: true,
},
},
invoiceNumber: {
number: {
type: 'string',
default: undefined,
'x-component-props': {
......@@ -56,7 +56,7 @@ export const schema: ISchema = {
allowClear: true,
},
},
"[createTimeStart, createTimeEnd]": {
"[invoiceStartDate, invoiceEndDate]": {
type: 'object',
'x-component': 'RangePicker',
'x-component-props': {
......
......@@ -4,14 +4,14 @@
import React, { useRef, useState } from 'react';
import { getIntl, useIntl, Link, history } from 'umi';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Card, Button, DatePicker, Space, Badge, Drawer, message } from 'antd';
import { Card, Button, DatePicker, Modal } from 'antd';
import NiceForm from '@/components/NiceForm';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { createFormActions } from '@formily/antd';
import StandardTable from '@/components/StandardTable';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
import { schema } from './schema';
import { refuseSchema, schema } from './schema';
import StatusTag from '../components/StatusTag';
import { fetchInvoiceOptions } from '../../../common';
import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable';
......@@ -19,19 +19,27 @@ import { numFormat, priceFormat } from '@/utils/numberFomat';
import {
getSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceListStatus,
getSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceList,
postSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceConfirm,
postSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceReturn,
} from '@/services/SettleV2Api';
import AuthButton from '@/components/AuthButton';
import './index.less';
import { PlusCircleOutlined } from '@ant-design/icons';
import moment from 'moment';
import TableOperation from '@/components/TableOperation';
import ModalForm from '@/components/ModalForm';
const intl = getIntl();
const RangePicker = DatePicker.RangePicker;
const formActions = createFormActions();
const refuseActions = createFormActions();
const InvoiceJoint: React.FC = () => {
const intl = useIntl();
const ref = useRef<any>({});
const { searchData, formatInitialValue } = useSetSearchValueInTable();
const [confirmLoading, setConfirmLoading] = useState<boolean>(false)
const refuseModalRef = useRef<any>({})
/**
* @param params
*/
......@@ -51,29 +59,92 @@ const InvoiceJoint: React.FC = () => {
* 搜索
*/
const handleSearch = values => {
const format = 'YYYY-MM-DD';
const payStartTime = values.payStartTime?.format(format);
const payEndTime = values.payEndTime
? values.payEndTime.endOf('day').format('YYYY-MM-DD HH:mm:ss')
: '';
const orderStartTime = values.orderStartTime?.format(format);
const orderEndTime = values.orderEndTime
? values.orderEndTime.endOf('day').format('YYYY-MM-DD HH:mm:ss')
: '';
const DATE_FORMAT = 'YYYY-MM-DD';
ref.current.reload({
...values,
payStartTime,
payEndTime,
orderStartTime,
orderEndTime,
startTime: values?.startTime ? values?.startTime.format(DATE_FORMAT) : undefined,
endTime: values?.endTime ? values?.endTime.format(DATE_FORMAT) : undefined,
});
};
const _handleOrderNo = record => {
window.open(
`/memberCenter/balance/businessReconciliation/search/preview?id=${record.reconciliationId}&no=${record.reconciliationNo}`,
);
};
const handleConfirm = (record) => {
Modal.confirm({
content: '是否确认发票?',
centered: true,
onOk: () => {
return new Promise(async(resolve, reject) => {
try {
const res = await postSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceConfirm({ id: record.id })
if (res.code === 1000) {
ref.current && ref.current.reload()
resolve(true)
} else {
reject()
}
} catch (error) {
reject()
}
})
}
})
}
const handleRefuseModal = (record) => {
refuseModalRef.current?.setVisible(true)
refuseActions.clearErrors()
refuseActions.setFieldValue('reconciliationId', record.reconciliationId)
refuseActions.setFieldValue('invoiceId', record.id)
}
const handleRefuse = async () => {
refuseActions.submit().then(async ({ values }) => {
const params = {
reconciliationId: values.reconciliationId,
invoiceId: values.invoiceId,
returnTime: moment(new Date()).format('YYYY-MM-DD HH:mm:ss'),
returnSource: values.returnSource
}
setConfirmLoading(true)
try {
const res = await postSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceReturn(params)
if (res.code === 1000) {
refuseModalRef.current?.setVisible(false)
ref.current && ref.current.reload()
}
setConfirmLoading(false)
} catch (error) {
setConfirmLoading(false)
}
})
}
const renderOptionButton = (record) => {
// 按钮权限code和操作字符映射
const btnAuthOfOperationTextMap = {
[intl.formatMessage({ id: 'balance.invoice.joint.buttonGroup.1', defaultMessage: '确认' })]: 'invoice.confirm',
[intl.formatMessage({ id: 'balance.invoice.joint.buttonGroup.2', defaultMessage: '退回' })]: 'invoice.refuse',
}
const buttonGroup = {
[intl.formatMessage({ id: 'balance.invoice.joint.buttonGroup.1', defaultMessage: '确认' })]: record.examineStatus === 1,
[intl.formatMessage({ id: 'balance.invoice.joint.buttonGroup.2', defaultMessage: '退回' })]: record.examineStatus === 1,
}
const operationHandler = {
[intl.formatMessage({ id: 'balance.invoice.joint.buttonGroup.1', defaultMessage: '确认' })]: () => handleConfirm(record),
[intl.formatMessage({ id: 'balance.invoice.joint.buttonGroup.2', defaultMessage: '退回' })]: () => handleRefuseModal(record),
}
return (
<TableOperation
buttonTextFieldMap={buttonGroup}
operationHandler={operationHandler}
// menuCode="commodityAbility"
buttonPermissionsMap={btnAuthOfOperationTextMap}
/>
)
}
const columns = [
{
......@@ -85,7 +156,8 @@ const InvoiceJoint: React.FC = () => {
<Button
type="link"
onClick={() => {
_handleOrderNo(record);
history.push(`/memberCenter/balance/invoiceJoint/detail?reconciliationId=${record.reconciliationId}&id=${record.id}`)
}}
>
{text}
......@@ -128,6 +200,7 @@ const InvoiceJoint: React.FC = () => {
id: 'balance.accountsReceivable.invoice.columns.invoiceDate',
}),
dataIndex: 'invoiceDate',
render: date => moment(date).format('YYYY-MM-DD')
},
{
title: intl.formatMessage({
......@@ -188,17 +261,7 @@ const InvoiceJoint: React.FC = () => {
title: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.operation',
}),
render: (_, record) => {
return (
<Link
to={`/memberCenter/balance/invoiceJoint/detail?id=${record.reconciliationId}`}
>
{intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.operation.1',
})}
</Link>
);
},
render: (_, record) => renderOptionButton(record)
},
];
......@@ -233,16 +296,32 @@ const InvoiceJoint: React.FC = () => {
schema={schema}
onSubmit={handleSearch}
onReset={() => {
formActions.setFieldValue('payStartTime', null);
formActions.setFieldValue('payEndTime', null);
formActions.setFieldValue('orderStartTime', null);
formActions.setFieldValue('orderEndTime', null);
formActions.setFieldValue('startTime', null);
formActions.setFieldValue('endTime', null);
}}
{...formatInitialValue}
/>
}
/>
</Card>
<ModalForm
modalTitle='退回原因'
width={450}
currentRef={refuseModalRef}
actions={refuseActions}
modalProps={{
centered: true,
confirmLoading
}}
previewPlaceholder=" "
schema={refuseSchema}
initialValues={{}}
confirm={handleRefuse}
cancel={() => {
refuseActions.reset()
refuseModalRef.current?.setVisible(false)
}}
/>
</PageHeaderWrapper>
);
};
......
......@@ -2,6 +2,7 @@ import { getIntl } from 'umi'
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { ISchema, createFormActions } from '@formily/antd';
import moment from 'moment';
const intl = getIntl()
/**
* 开票管理列表页schema
......@@ -64,7 +65,7 @@ export const schema: ISchema = {
allowClear: true,
},
},
"[createTimeStart, createTimeEnd]": {
"[startTime, startTime]": {
type: 'object',
'x-component': 'RangePicker',
'x-component-props': {
......@@ -96,3 +97,57 @@ export const schema: ISchema = {
},
},
};
/** 退回原因 */
export const refuseSchema: ISchema = {
type: 'object',
properties: {
NO_SUBMIT: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelAlign: 'top',
},
properties: {
reconciliationId: {
type: 'string',
visible: false,
},
invoiceId: {
type: 'string',
visible: false,
},
returnTime: {
type: 'string',
readOnly: true,
title: '退回时间',
default: moment(new Date()).format('YYYY-MM-DD HH:mm:ss')
},
returnSource: {
type: 'textarea',
title: '退回原因',
"x-component-props": {
with: '100%',
rows: 4,
allowClear: true,
placeholder: '请输入退回原因',
style: {
resize: 'none'
}
},
"x-rules": [
{
required: true,
message: getIntl().formatMessage({ id: 'balance.invoice.returnSource.required', defaultMessage: '请输入退回原因' }),
},
{
limitByte: true,
maxByte: 100,
message: '最大100个字符,50个文字'
}
]
}
}
}
}
}
......@@ -148,6 +148,7 @@ export const statementsColumn = [
defaultMessage: '税率'
}),
dataIndex: 'taxRate',
render: (taxRate) => `${taxRate}%`
},
{
title: intl.formatMessage({
......@@ -158,17 +159,17 @@ export const statementsColumn = [
},
{
title: intl.formatMessage({
id: 'balance.invoice.columns.reconciliationQuantity',
id: 'balance.invoice.columns.currentReconciliationQuantity',
defaultMessage: '对账数量'
}),
dataIndex: 'reconciliationQuantity',
dataIndex: 'currentReconciliationQuantity',
},
{
title: intl.formatMessage({
id: 'balance.invoice.columns.reconciliationMoneyAmount',
id: 'balance.invoice.columns.currentMoney',
defaultMessage: '对账金额(含税)'
}),
dataIndex: 'reconciliationMoneyAmount',
dataIndex: 'currentMoney',
},
]
......@@ -178,6 +179,7 @@ export const invoiceDetailColumn = [
id: 'balance.invoice.columns.orderNo',
defaultMessage: '订单号'
}),
width: 110,
dataIndex: 'orderNo',
},
{
......@@ -185,6 +187,7 @@ export const invoiceDetailColumn = [
id: 'balance.invoice.columns.deliveryNo',
defaultMessage: '发货单号'
}),
width: 110,
dataIndex: 'deliveryNo',
},
{
......@@ -192,6 +195,7 @@ export const invoiceDetailColumn = [
id: 'balance.invoice.columns.receiveNo',
defaultMessage: '收货单号'
}),
width: 110,
dataIndex: 'receiveNo',
},
{
......@@ -257,13 +261,13 @@ export const invoiceDetailColumn = [
defaultMessage: '单价(不含税)'
}),
dataIndex: 'priceNoTax',
// render: (_, record) => `${(record.price / (1 + (record.taxRate / 100))).toFixed(2)}`
},
{
title: intl.formatMessage({
id: 'balance.invoice.columns.quantity',
defaultMessage: '数量'
}),
width: 80,
editable: true,
formItem: 'number',
dataIndex: 'currentNumber',
......@@ -274,7 +278,6 @@ export const invoiceDetailColumn = [
defaultMessage: '金额(含税)'
}),
dataIndex: 'currentMoneyAmount',
// render: (_, record) => `${(record.price * record.currentReconciliationQuantity).toFixed(2)}`
},
{
title: intl.formatMessage({
......@@ -282,7 +285,6 @@ export const invoiceDetailColumn = [
defaultMessage: '金额(不含税)'
}),
dataIndex: 'currentMoneyNoTax',
// render: (_, record) => `${((record.price * record.currentReconciliationQuantity) / (1 + (record.taxRate / 100))).toFixed(2)}`
},
{
title: intl.formatMessage({
......@@ -290,7 +292,6 @@ export const invoiceDetailColumn = [
defaultMessage: '税额'
}),
dataIndex: 'taxMoneyAmount',
// render: (_, record) => `${((record.price * record.currentReconciliationQuantity) / (1 + (record.taxRate / 100)) * (record.taxRate / 100)).toFixed(2)}`
},
{
title: intl.formatMessage({
......@@ -299,5 +300,6 @@ export const invoiceDetailColumn = [
}),
width: 80,
action: 'delete',
fixed: 'right',
},
]
import React from 'react'
import { useIntl } from 'umi'
import { usePageStatus } from '@/hooks/usePageStatus'
import InvoiceForm, { OperateType } from './invoiceForm'
const InvoiceDetail: React.FC = () => {
const { reconciliationId, id } = usePageStatus()
const intl = useIntl()
return (
<InvoiceForm
title={intl.formatMessage({
id: 'balance.invoice.detail.page.title',
defaultMessage: '发票详情',
})}
reconciliationId={Number(reconciliationId)}
id={Number(id)}
type={OperateType.detail}
/>
)
}
export default InvoiceDetail
import React from 'react'
import { useIntl } from 'umi'
import { usePageStatus } from '@/hooks/usePageStatus'
import InvoiceForm, { OperateType } from './invoiceForm'
const InvoiceEdit: React.FC = () => {
const { reconciliationId, id } = usePageStatus()
const intl = useIntl()
return (
<InvoiceForm
title={intl.formatMessage({
id: 'balance.invoice.edit.page.title',
defaultMessage: '编辑发票',
})}
reconciliationId={Number(reconciliationId)}
id={Number(id)}
type={OperateType.edit}
/>
)
}
export default InvoiceEdit
/**
* 开票管理(SRM)
*/
import React, { useRef } from 'react';
import { getIntl, useIntl, Link, history } from 'umi';
import React, { useRef, useState } from 'react';
import { getIntl, useIntl, history } from 'umi';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Card, Button, DatePicker, Space } from 'antd';
import { Card, Button, DatePicker, Space, message, Modal } from 'antd';
import NiceForm from '@/components/NiceForm';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { createFormActions } from '@formily/antd';
import StandardTable from '@/components/StandardTable';
import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilterSearch';
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
import { schema } from './schema';
import { fetchOptions } from '../../../common';
import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable';
import { priceFormat } from '@/utils/numberFomat';
import StatusTag from '../components/StatusTag'
import {
getSettleAccountsMemberSettlementAccountStatementInvoiceList,
postSettleAccountsMemberSettlementAccountStatementSubmit,
postSettleAccountsMemberSettlementAccountStatementDelete,
} from '@/services/SettleV2Api';
import AuthButton from '@/components/AuthButton';
import './index.less';
import { PlusCircleOutlined } from '@ant-design/icons';
import moment from 'moment';
import TableOperation from '@/components/TableOperation';
const intl = getIntl();
const RangePicker = DatePicker.RangePicker;
......@@ -30,19 +31,21 @@ const formActions = createFormActions();
const InvoiceManage: React.FC = () => {
const intl = useIntl();
const ref = useRef<any>({});
const { searchData, formatInitialValue } = useSetSearchValueInTable();
const [pageLoading, setPageLoading] = useState<boolean>(false)
/**
* @param params
*/
const fetchListData = async params => {
setPageLoading(true)
const searchParams = {
...params,
...searchData,
orderByCode: 1,
};
const { data } = await getSettleAccountsMemberSettlementAccountStatementInvoiceList(
searchParams,
);
setPageLoading(false)
return data;
};
......@@ -50,29 +53,80 @@ const InvoiceManage: React.FC = () => {
* 搜索
*/
const handleSearch = values => {
const format = 'YYYY-MM-DD';
const payStartTime = values.payStartTime?.format(format);
const payEndTime = values.payEndTime
? values.payEndTime.endOf('day').format('YYYY-MM-DD HH:mm:ss')
: '';
const orderStartTime = values.orderStartTime?.format(format);
const orderEndTime = values.orderEndTime
? values.orderEndTime.endOf('day').format('YYYY-MM-DD HH:mm:ss')
: '';
ref.current.reload({
...values,
payStartTime,
payEndTime,
orderStartTime,
orderEndTime,
invoiceStartDate: values?.invoiceStartDate ? values?.invoiceStartDate.format('YYYY-MM-DD HH:mm:ss') : undefined,
invoiceEndDate: values?.invoiceEndDate ? values?.invoiceEndDate.format('YYYY-MM-DD HH:mm:ss') : undefined,
});
};
const _handleOrderNo = record => {
window.open(
`/memberCenter/balance/businessReconciliation/search/preview?id=${record.reconciliationId}&no=${record.reconciliationNo}`,
);
};
/** 提交开票数据 */
const handleSubmit = async (record) => {
const res = await postSettleAccountsMemberSettlementAccountStatementSubmit({ id: record.id })
if (res.code === 1000) {
ref.current && ref.current.reload()
}
}
/** 删除发票 */
const handleDelete = async (record) => {
Modal.confirm({
content: '是否确认删除发票?',
centered: true,
onOk: () => {
return new Promise(async(resolve, reject) => {
try {
const res = await postSettleAccountsMemberSettlementAccountStatementDelete({ invoiceId: record.id })
if (res.code === 1000) {
ref.current && ref.current.reload()
resolve(true)
} else {
reject()
}
} catch (error) {
reject()
}
})
}
})
}
/** 跳转到编辑页面 */
const handleEdit = (record) => {
history.push(`/memberCenter/balance/invoice/edit?reconciliationId=${record.reconciliationId}&id=${record.id}`)
}
const renderOptionButton = (record) => {
// 按钮权限code和操作字符映射
const btnAuthOfOperationTextMap = {
[intl.formatMessage({ id: 'balance.invoice.manage.buttonGroup.1', defaultMessage: '提交' })]: 'invoice.sbumt',
[intl.formatMessage({ id: 'balance.invoice.manage.buttonGroup.2', defaultMessage: '编辑' })]: 'invoice.edit',
[intl.formatMessage({ id: 'balance.invoice.manage.buttonGroup.3', defaultMessage: '删除' })]: 'invoice.del',
}
const buttonGroup = {
[intl.formatMessage({ id: 'balance.invoice.manage.buttonGroup.1', defaultMessage: '提交' })]: record.examineStatus === 0,
[intl.formatMessage({ id: 'balance.invoice.manage.buttonGroup.2', defaultMessage: '编辑' })]: [0, 3].includes(record.examineStatus),
[intl.formatMessage({ id: 'balance.invoice.manage.buttonGroup.3', defaultMessage: '删除' })]: [0, 3].includes(record.examineStatus),
}
const operationHandler = {
[intl.formatMessage({ id: 'balance.invoice.manage.buttonGroup.1', defaultMessage: '提交' })]: () => handleSubmit(record),
[intl.formatMessage({ id: 'balance.invoice.manage.buttonGroup.2', defaultMessage: '编辑' })]: () => handleEdit(record),
[intl.formatMessage({ id: 'balance.invoice.manage.buttonGroup.3', defaultMessage: '删除' })]: () => handleDelete(record),
}
return (
<TableOperation
buttonTextFieldMap={buttonGroup}
operationHandler={operationHandler}
// menuCode="commodityAbility"
buttonPermissionsMap={btnAuthOfOperationTextMap}
/>
)
}
const columns = [
{
......@@ -84,7 +138,7 @@ const InvoiceManage: React.FC = () => {
<Button
type="link"
onClick={() => {
_handleOrderNo(record);
history.push(`/memberCenter/balance/invoice/detail?reconciliationId=${record.reconciliationId}&id=${record.id}`)
}}
>
{text}
......@@ -133,6 +187,7 @@ const InvoiceManage: React.FC = () => {
id: 'balance.accountsReceivable.invoice.columns.invoiceDate',
}),
dataIndex: 'invoiceDate',
render: invoiceDate => moment(invoiceDate).format('YYYY-MM-DD')
},
{
title: intl.formatMessage({
......@@ -193,17 +248,7 @@ const InvoiceManage: React.FC = () => {
title: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.operation',
}),
render: (_, record) => {
return (
<Link
to={`/memberCenter/balance/invoice/detail?id=${record.reconciliationId}`}
>
{intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.operation.1',
})}
</Link>
);
},
render: (_, record) => renderOptionButton(record)
},
];
......@@ -231,6 +276,7 @@ const InvoiceManage: React.FC = () => {
tableProps={{
rowKey: 'id',
}}
loading={pageLoading}
columns={columns as any}
currentRef={ref}
fetchTableData={(params: any) => fetchListData(params)}
......@@ -253,13 +299,7 @@ const InvoiceManage: React.FC = () => {
}}
schema={schema}
onSubmit={handleSearch}
onReset={() => {
formActions.setFieldValue('payStartTime', null);
formActions.setFieldValue('payEndTime', null);
formActions.setFieldValue('orderStartTime', null);
formActions.setFieldValue('orderEndTime', null);
}}
{...formatInitialValue}
initialValues={{}}
/>
}
/>
......
This diff is collapsed.
......@@ -4,6 +4,7 @@ import { invoiceDetailColumn } from '../contants';
import ProductTableCell, { ProductEditableRow } from '../../components/ProductTableCell';
import { getIntl } from 'umi';
import { Button } from 'antd';
import { OperateType } from '../invoiceForm';
const intl = getIntl();
......@@ -53,6 +54,18 @@ export const useInvoiceDetailTable = (ctx: ISchemaFormActions | ISchemaFormAsync
const invoiceMergeColumns = invoiceDetailColumn.map(col => {
const operateType = ctx.getFieldValue('operateType')
if (operateType === OperateType.detail) {
if (col.action && col.action === 'delete') {
return {
key: 'action'
}
}
return col;
}
if (col.action && col.action === 'delete') {
return {
...col,
......
......@@ -51,7 +51,7 @@ export const schema: ISchema = {
allowClear: true,
},
},
invoiceNumber: {
number: {
type: 'string',
default: undefined,
'x-component-props': {
......@@ -59,7 +59,7 @@ export const schema: ISchema = {
allowClear: true,
},
},
"[createTimeStart, createTimeEnd]": {
"[invoiceStartDate, invoiceEndDate]": {
type: 'object',
'x-component': 'RangePicker',
'x-component-props': {
......@@ -84,6 +84,76 @@ export const schema: ISchema = {
},
};
/**
* 选择单据搜索schema
*/
export const searchSchema: ISchema = {
type: 'object',
properties: {
megaLayout: {
type: 'object',
'x-component': 'mega-layout',
'x-component-props': {
grid: true,
},
properties: {
reconciliationNo: {
type: 'string',
'x-component': 'Search',
'x-component-props': {
allowClear: true,
align: 'flex-start',
placeholder: intl.formatMessage({ id: 'balance.accountsReceivable.invoice.schema.orderNo' }),
},
},
},
},
[FORM_FILTER_PATH]: {
type: 'object',
'x-component': 'flex-layout',
'x-component-props': {
rowStyle: {
flexWrap: 'nowrap',
justifyContent: 'flex-start'
},
colStyle: {
marginRight: 16,
},
},
properties: {
reconciliationAbstract: {
type: 'string',
default: undefined,
'x-component-props': {
placeholder: intl.formatMessage({ id: 'balance.accountsReceivable.invoice.schema.orderAbstract' }),
allowClear: true,
},
},
"[createTimeStart, createTimeEnd]": {
type: 'object',
'x-component': 'RangePicker',
'x-component-props': {
placeholder: [intl.formatMessage({ id: 'balance.accountsReceivable.invoice.schema.invoiceStartTime' }), intl.formatMessage({ id: 'balance.accountsReceivable.invoice.schema.invoiceEndTime' })],
allowClear: true,
style: {
width: 320,
}
},
},
submit: {
'x-component': 'Submit',
'x-mega-props': {
span: 1,
},
'x-component-props': {
children: intl.formatMessage({ id: 'balance.accountsReceivable.invoice.schema.submit' }),
},
},
},
},
},
};
// 单据信息
const receiptInfo: ISchema = {
"x-index": 0,
......@@ -107,11 +177,15 @@ const receiptInfo: ISchema = {
columns: 2,
},
properties: {
id: {
type: 'string',
readOnly: true,
visible: false,
},
reconciliationId: {
type: 'string',
readOnly: true,
visible: false,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.reconciliationId', defaultMessage: '对账单ID' }),
},
reconciliationNo: {
type: 'string',
......@@ -275,8 +349,26 @@ const billInfo: ISchema = {
columns: 2,
},
properties: {
operateType: {
type: 'string',
visible: false,
"x-linkages": [
{
type: 'value:state',
target: '*(code,invoiceDate,number,remark,urlImgs)',
condition: '{{ $value === "detail"}}',
state: {
editable: false
},
otherwise: {
editable: true
}
}
],
},
code: {
type: 'string',
readOnly: true,
title: intl.formatMessage({ id: 'balance.common.columns.productNoticecolumns.code', defaultMessage: '发票代码' }),
"x-component-props": {
placeholder: '最长20个字符',
......@@ -340,7 +432,7 @@ const billInfo: ISchema = {
urlImgs: {
type: 'string',
"x-component": "UploadInvoice",
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.urlImgs', defaultMessage: '发票图片' }),
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.urlImgs', defaultMessage: '发票文件' }),
},
},
}
......@@ -355,6 +447,7 @@ const invoiceDetails: ISchema = {
"x-component-props": {
title: getIntl().formatMessage({ id: 'balance.invoice.manage.addSchema.invoiceDetails', defaultMessage: '发票明细' }),
id: 'invoiceDetails',
showTotal: true,
},
properties: {
rows: {
......@@ -365,6 +458,9 @@ const invoiceDetails: ISchema = {
columns: "{{invoiceDetailColumns}}",
components: "{{invoiceDetailComponents}}",
prefix: "{{SelectStatementsButton}}",
scroll: {
x: 1800
},
},
"x-rules": [
{
......
/**
* 待开票(SRM)
*/
import React, { useRef, useState } from 'react';
import React, { useRef } from 'react';
import { getIntl, useIntl, Link } from 'umi';
import { PageHeaderWrapper } from '@ant-design/pro-layout';
import { Card, Button, DatePicker, Space, message } from 'antd';
import { Card, Button, DatePicker } from 'antd';
import NiceForm from '@/components/NiceForm';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { createFormActions } from '@formily/antd';
......@@ -23,6 +23,7 @@ import {
} from '@/services/SettleV2Api';
import AuthButton from '@/components/AuthButton';
import './index.less';
import moment from 'moment';
const intl = getIntl();
const RangePicker = DatePicker.RangePicker;
......@@ -31,7 +32,6 @@ const formActions = createFormActions();
const SettlementList: React.FC = () => {
const intl = useIntl();
const ref = useRef<any>({});
const { searchData, formatInitialValue } = useSetSearchValueInTable();
/**
* @param params
......@@ -39,7 +39,6 @@ const SettlementList: React.FC = () => {
const fetchListData = async params => {
const searchParams = {
...params,
...searchData,
};
const { data } = await getSettleAccountsMemberSettlementPageInvoicingProcessList(
searchParams,
......@@ -51,21 +50,10 @@ const SettlementList: React.FC = () => {
* 搜索
*/
const handleSearch = values => {
const format = 'YYYY-MM-DD';
const payStartTime = values.payStartTime?.format(format);
const payEndTime = values.payEndTime
? values.payEndTime.endOf('day').format('YYYY-MM-DD HH:mm:ss')
: '';
const orderStartTime = values.orderStartTime?.format(format);
const orderEndTime = values.orderEndTime
? values.orderEndTime.endOf('day').format('YYYY-MM-DD HH:mm:ss')
: '';
ref.current.reload({
...values,
payStartTime,
payEndTime,
orderStartTime,
orderEndTime,
createTimeStart: values?.createTimeStart ? values?.createTimeStart.format('YYYY-MM-DD') : undefined,
createTimeEnd: values?.createTimeEnd ? values?.createTimeEnd.format('YYYY-MM-DD') : undefined,
});
};
......@@ -110,6 +98,7 @@ const SettlementList: React.FC = () => {
id: 'balance.accountsReceivable.invoice.columns.orderTime',
}),
dataIndex: 'createTime',
render: createTime => moment(createTime).format('YYYY-MM-DD')
},
{
title: intl.formatMessage({
......@@ -180,7 +169,7 @@ const SettlementList: React.FC = () => {
<Link
to={
record.invoiceStatus === 1
? `/memberCenter/balance/invoice/inquire?reconciliationId=${record.reconciliationId}`
? `/memberCenter/balance/invoice/inquire?reconciliationNo=${record.reconciliationNo}`
: `/memberCenter/balance/invoice/add?reconciliationId=${record.reconciliationId}`
}
>
......@@ -227,11 +216,11 @@ const SettlementList: React.FC = () => {
}}
schema={schema}
onSubmit={handleSearch}
initialValues={{}}
onReset={() => {
formActions.setFieldValue('orderStartTime', null);
formActions.setFieldValue('orderEndTime', null);
formActions.setFieldValue('createTimeStart', null);
formActions.setFieldValue('createTimeEnd', null);
}}
{...formatInitialValue}
/>
}
/>
......
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