Commit 36decc83 authored by GuanHua's avatar GuanHua

feat: 新增开票开发

parents 5eaaae7e 426464fd
...@@ -19,10 +19,10 @@ pipeline { ...@@ -19,10 +19,10 @@ pipeline {
environment { environment {
// 项目名称 // 项目名称
SERVER_NAME = "platform" SERVER_NAME = "platform"
BUILD_ENV = "v2-220418" BUILD_ENV = "v2-220518"
// ssh 传输信息 // ssh 传输信息
SSH_NAME = "linkseeks-v2-220418" SSH_NAME = "linkseeks-v2-220518"
SSH_FILE_SOURCE_NAME = "platform.tar.gz" SSH_FILE_SOURCE_NAME = "platform.tar.gz"
// 远程存放压缩包的路径 // 远程存放压缩包的路径
SSH_REMOTE_PATH = "/home/www/platform" SSH_REMOTE_PATH = "/home/www/platform"
......
...@@ -109,6 +109,27 @@ const AuthConfigRoute: RouterChild = { ...@@ -109,6 +109,27 @@ const AuthConfigRoute: RouterChild = {
}, },
] ]
}, },
// 流程引擎
{
path: '/memberCenter/systemSetting/processEng',
name: '流程引擎',
routes: [
{
// 请款单流程规则配置
path: '/memberCenter/systemSetting/processEng/invoiceProcessEng',
name: '请款单流程规则配置',
component: '@/pages/systemSetting/processEng/invoiceProcessEng',
},
{
// 新增请款单流程规则
path: '/memberCenter/systemSetting/processEng/invoiceProcessEng/add',
name: '新增请款单流程规则',
component: '@/pages/systemSetting/processEng/invoiceProcessEng/add',
hideInMenu: true,
noMargin: true,
},
]
},
/** 密钥管理 */ /** 密钥管理 */
{ {
path: '/memberCenter/systemSetting/key', path: '/memberCenter/systemSetting/key',
......
...@@ -455,6 +455,81 @@ const BalancedRoute = { ...@@ -455,6 +455,81 @@ const BalancedRoute = {
hideInMenu: true, hideInMenu: true,
noMargin: true, noMargin: true,
}, },
{
path: '/memberCenter/balance/businessRequestFunds/one',
component: '@/pages/balance/businessRequestFunds/one',
relationParentCode: 'balance',
name: '待审核请款单 (一级)',
icon: 'smile',
},
{
path: '/memberCenter/balance/businessRequestFunds/one/preview',
component: '@/pages/balance/businessRequestFunds/detail',
relationParentCode: 'balance',
name: '待审核请款单 (一级)-详情',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
{
path: '/memberCenter/balance/businessRequestFunds/one/detail',
component: '@/pages/balance/businessRequestFunds/detail',
relationParentCode: 'balance',
name: '待审核请款单 (一级)-详情',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
{
path: '/memberCenter/balance/businessRequestFunds/two',
component: '@/pages/balance/businessRequestFunds/two',
relationParentCode: 'balance',
name: '待审核请款单 (二级)',
icon: 'smile',
},
{
path: '/memberCenter/balance/businessRequestFunds/two/preview',
component: '@/pages/balance/businessRequestFunds/detail',
relationParentCode: 'balance',
name: '待审核请款单 (二级)-详情',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
{
path: '/memberCenter/balance/businessRequestFunds/two/detail',
component: '@/pages/balance/businessRequestFunds/detail',
relationParentCode: 'balance',
name: '待审核请款单 (二级)-详情',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
{
path: '/memberCenter/balance/businessRequestFunds/submit',
component: '@/pages/balance/businessRequestFunds/submit',
relationParentCode: 'balance',
name: '待提交请款单',
icon: 'smile',
},
{
path: '/memberCenter/balance/businessRequestFunds/submit/preview',
component: '@/pages/balance/businessRequestFunds/detail',
relationParentCode: 'balance',
name: '待提交请款单-详情',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
{
path: '/memberCenter/balance/businessRequestFunds/submit/detail',
component: '@/pages/balance/businessRequestFunds/detail',
relationParentCode: 'balance',
name: '待提交请款单-详情',
icon: 'smile',
hideInMenu: true,
noMargin: true,
},
], ],
}, },
// 业务请款协同 // 业务请款协同
...@@ -528,7 +603,7 @@ const BalancedRoute = { ...@@ -528,7 +603,7 @@ const BalancedRoute = {
"component": "@/pages/balance/invoice/srm/inquire", "component": "@/pages/balance/invoice/srm/inquire",
"relationParentCode": "balance", "relationParentCode": "balance",
"name": "发票查询", "name": "发票查询",
"hideInMenu": true, // "hideInMenu": true,
"icon": "smile", "icon": "smile",
"btns": [] "btns": []
}, },
......
...@@ -11,7 +11,7 @@ import CommodityRoute from './commodityRoute'; // 商品能力路由 ...@@ -11,7 +11,7 @@ import CommodityRoute from './commodityRoute'; // 商品能力路由
import TranactionRoute from './tranactionRoute'; // 交易能力路由 import TranactionRoute from './tranactionRoute'; // 交易能力路由
// import LogisticsRoute from './logisticsRoutes' // 物流能力路由 // import LogisticsRoute from './logisticsRoutes' // 物流能力路由
// import PayandSettleRoute from './payandSettle' //支付与结算 // import PayandSettleRoute from './payandSettle' //支付与结算
// import AuthConfigRoute from './authConfigRoute' import AuthConfigRoute from './authConfigRoute'
// import AfterService from './afterServiceRoute' // 售后 // import AfterService from './afterServiceRoute' // 售后
// import HandlingRoute from './handlingRoute'; // 加工能力 // import HandlingRoute from './handlingRoute'; // 加工能力
// import DealAbilityRoute from './dealAbilityRoute'; // // import DealAbilityRoute from './dealAbilityRoute'; //
......
...@@ -214,5 +214,12 @@ module.exports = { ...@@ -214,5 +214,12 @@ module.exports = {
USE_ROUTE_CONFIG: true, USE_ROUTE_CONFIG: true,
SOCKET_URL: 'ws://10.0.1.146:9880', SOCKET_URL: 'ws://10.0.1.146:9880',
YAPI_URL: 'http://10.0.0.25:4000/' YAPI_URL: 'http://10.0.0.25:4000/'
},
"v2-220518": {
SITE_ID: '1',
BACK_GATEWAY: 'http://10.0.1.156:8100',
USE_ROUTE_CONFIG: true,
SOCKET_URL: 'ws://10.0.1.156:9880',
YAPI_URL: 'http://10.0.0.25:4000/'
} }
} }
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
"start:v2scm": "cross-env PRO_ENV=v2scm yarn start", "start:v2scm": "cross-env PRO_ENV=v2scm yarn start",
"start:v2-220318": "cross-env PRO_ENV=v2-220318 yarn start", "start:v2-220318": "cross-env PRO_ENV=v2-220318 yarn start",
"start:v2-220418": "cross-env PRO_ENV=v2-220418 yarn start", "start:v2-220418": "cross-env PRO_ENV=v2-220418 yarn start",
"start:v2-220518": "cross-env PRO_ENV=v2-220518 yarn start",
"start-fast": "cross-env NODE_OPTIONS=--max_old_space_size=4096 UMI_ENV=local umi dev", "start-fast": "cross-env NODE_OPTIONS=--max_old_space_size=4096 UMI_ENV=local umi dev",
"start-fast:v2-220418": "cross-env PRO_ENV=v2-220418 yarn start-fast", "start-fast:v2-220418": "cross-env PRO_ENV=v2-220418 yarn start-fast",
"start:ali": "cross-env PRO_ENV=v2-ali-demo yarn start" "start:ali": "cross-env PRO_ENV=v2-ali-demo yarn start"
......
import React, { useEffect, useRef, useState } from 'react';
import { ISchema } from '@formily/antd';
import { useIntl } from 'umi';
import { Modal, Row, Col, Drawer,Button } from 'antd';
import { createFormActions } from '@formily/antd';
import StandardTable from '@/components/StandardTable';
import { ColumnsType } from 'antd/es/table';
import NiceForm from '@/components/NiceForm';
const formActions = createFormActions();
interface Iprops {
modalType?: "Modal" | "Drawer"
/**
* 是否显示
*/
visible: boolean,
/**
* Modal 标题
*/
title: string,
/**
* 搜索schema
*/
schema: ISchema,
/**
* table Ccolumn
*/
columns: ColumnsType,
footer?: React.ReactNode,
tableProps?: {
rowKey: string | ((record) => any),
expandable?: any,
},
width?: number,
mode: 'checkbox' | 'radio',
customizeRadio?: boolean,
/** 回显值 */
value?: {[key: string]: any}[],
/**
* onChange
*/
expressionScope?: {[key: string]: any}
/**
* format话参数
*/
format?: ((value) => any) | null,
components?: { [key: string]: any },
effects?: ($, actions) => void,
fetchData: (params: any) => any,
onClose: () => void,
onOk: (selectRow: number[] | string[], selectedRows: {[key: string]: any}[]) => void,
/**
* 勾选前操作,
*/
beforeChecked?: ((record: any, selected: boolean, selectedRows: any[]) => boolean) | ((record: any, selected: boolean, selectedRows: any[]) => Promise<any>),
/**
* rowSelection
*/
rowSelection?: {
getCheckboxProps?: (record) => any,
}
}
const TableModal: React.FC<Iprops> = (props: Iprops) => {
const {
title,
visible,
schema,
columns,
effects,
tableProps,
mode,
expressionScope,
fetchData,
onClose,
onOk,
value,
format,
customizeRadio,
modalType,
footer,
width,
components,
beforeChecked,
rowSelection
} = props;
const ref = useRef<any>({});
const isFirstLoad = useRef<boolean>(true)
const [selectRow, setSelectRow] = useState<number[] | string[]>(() => {
return value.map( (_row) => typeof tableProps.rowKey === 'string' ? _row[tableProps.rowKey as string] : tableProps.rowKey(_row))
})
const [selectRowRecord, setSelectRowRecord] = useState<{[key: string]: any}[]>([]);
const intl = useIntl();
useEffect(() => {
if (!visible) {
return;
}
let list = value;
const currentMode = customizeRadio || mode === 'radio';
if (currentMode) {
list = list.slice(-1);
}
const keys = list.map(
(_row) => {
// console.log(typeof tableProps.rowKey === 'string' && tableProps.rowKey(_row))
return typeof tableProps.rowKey === 'string' ? _row[tableProps.rowKey as string] : tableProps.rowKey(_row)
});
setSelectRow(keys)
setSelectRowRecord(value);
}, [visible, value, mode, customizeRadio])
const handleEffects = ($: any, actions: any) => {
effects?.($, actions);
}
const handleOnClose = () => {
onClose?.()
}
const handleOk = () => {
onOk?.(selectRow, selectRowRecord)
}
useEffect(() => {
if (!visible) {
return ;
}
if (!isFirstLoad.current) {
ref.current?.reload?.();
}
isFirstLoad.current = false;
}, [visible])
const onSelectChange = async (record, selected: boolean, selectedRows) => {
const recordRows = customizeRadio || mode === 'radio' ? selectedRows.slice(-1) : selectedRows;
const keys = recordRows.map((_item) => typeof tableProps.rowKey === 'string' ? _item[tableProps.rowKey as string] : tableProps.rowKey(_item));
// if (selected) {
const returnValue =await beforeChecked(record, selected, recordRows);
if (returnValue === false) {
return;
}
// }
setSelectRowRecord(recordRows)
setSelectRow(keys)
};
const onSelectAll = async (selected: boolean, selectedRows: any[], changeRows: any[]) => {
const keys = selectedRows.map((_item) => typeof tableProps.rowKey === 'string' ? _item[tableProps.rowKey as string] : tableProps.rowKey(_item));
setSelectRowRecord(selectedRows)
setSelectRow(keys)
}
const handleSearch = (params: any) => {
const res = (format && format(params)) || params;
ref.current?.reload(res)
}
const Component = modalType === 'Modal' ? Modal : Drawer;
const renderFooter = () => {
return (
<div style={{ textAlign: 'right'}}>
<Button onClick={handleOnClose} style={{ marginRight: 8 }}>
{intl.formatMessage({ id: 'member.actions.cancel' })}
</Button>
<Button onClick={handleOk} type="primary">
{intl.formatMessage({ id: 'member.actions.confirm' })}
</Button>
</div>
)
}
const otherProps = modalType === 'Drawer' ? { footer: renderFooter(), maskClosable: true, onClose: handleOnClose } : { onOk: handleOk}
return (
<Component
title={title}
visible={visible}
onCancel={handleOnClose}
// onOk={handleOk}
width={width}
{...otherProps}
>
<StandardTable
columns={columns}
tableProps={{
...tableProps,
pagination: false
}}
keepAlive={false}
fetchTableData={fetchData}
currentRef={ref}
rowSelection={{
type: customizeRadio && mode === 'radio' ? 'checkbox' : mode,
onSelect: onSelectChange,
onSelectAll: onSelectAll,
selectedRowKeys: selectRow,
hideSelectAll: customizeRadio,
...rowSelection
}}
formRender={(child, ps) => (
// <div style={{display: "flex", flexDirection: 'row', justifyContent: 'space-between'}}>
// <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>
)}
controlRender={
<NiceForm
schema={schema}
components={components}
actions={formActions}
onSubmit={handleSearch}
expressionScope={expressionScope}
effects={($, actions) => handleEffects($, actions)}
/>
}
>
</StandardTable>
</Component>
)
}
TableModal.defaultProps = {
rowSelection: {},
mode: 'radio',
tableProps: {
rowKey: 'memberId'
},
value: [],
expressionScope: {},
format: null,
customizeRadio: false,
modalType: "Modal",
footer: null,
width: 840,
components: {},
beforeChecked: () => true
}
export default TableModal;
import { getIntl } from 'umi';
/** 请款单号 */
export const applyNo = {
title: getIntl().formatMessage({ id: 'balance.components.writeOffDrawer.columns.applyNo', defaultMessage: '请款单号' }),
key: 'applyNo',
dataIndex: 'applyNo',
}
/** 请款单摘要 */
export const applyAbstract = {
title: getIntl().formatMessage({ id: 'balance.businessRequestFundsCollaboration.detail.col.applyAbstract', defaultMessage: '请款摘要' }),
key: 'applyAbstract',
dataIndex: 'applyAbstract',
}
/** 请款类型 */
export const applyType = {
title: getIntl().formatMessage({ id: 'balance.businessRequestFundsCollaboration.detail.col.applyTypeName', defaultMessage: '请款类型' }),
key: 'applyType',
dataIndex: 'applyType',
}
/** 收款方 */
export const payee = {
title: getIntl().formatMessage({ id: 'balance.businessRequestFundsCollaboration.detail.col.payee', defaultMessage: '收款方' }),
key: 'payee',
dataIndex: 'payee',
}
/** 请款金额 */
export const applyAmount = {
title: getIntl().formatMessage({ id: 'balance.businessRequestFundsCollaboration.detail.col.applyAmount', defaultMessage: '请款金额' }),
key: 'applyAmount',
dataIndex: 'applyAmount',
}
/** 预计付款日期 */
export const expectPayTime = {
title: getIntl().formatMessage({ id: 'balance.businessRequestFundsCollaboration.detail.col.expectPayTime', defaultMessage: '预计付款日期' }),
key: 'expectPayTime',
dataIndex: 'expectPayTime',
}
/** 单据时间 */
export const createTime = {
title: getIntl().formatMessage({ id: 'balance.businessRequestFundsCollaboration.detail.columns.billTime', defaultMessage: '单据时间' }),
key: 'createTime',
dataIndex: 'createTime',
}
/** 内部状态 */
export const interiorStateName = {
title: getIntl().formatMessage({ id: 'components.neibuzhuangtai', defaultMessage: '内部状态' }),
key: 'interiorStateName',
dataIndex: 'interiorStateName',
}
/** 操作 */
export const operation = {
title: getIntl().formatMessage({ id: 'balance.settleRules.memberSettle.columns.operation', defaultMessage: '操作' }),
key: 'operation',
dataIndex: 'operation',
}
...@@ -15,6 +15,7 @@ import CommonLayout from '@/pages/transaction/purchaseAbility/components/detail/ ...@@ -15,6 +15,7 @@ import CommonLayout from '@/pages/transaction/purchaseAbility/components/detail/
import { getSettleAccountsBusinessApplyAmountDetailApplyAmount, getSettleAccountsBusinessApplyAmountApplyAmountRowList, postSettleAccountsBusinessApplyAmountFindCanApplyAmountRos } from '@/services/SettleV2Api' import { getSettleAccountsBusinessApplyAmountDetailApplyAmount, getSettleAccountsBusinessApplyAmountApplyAmountRowList, postSettleAccountsBusinessApplyAmountFindCanApplyAmountRos } from '@/services/SettleV2Api'
import WriteOffDrawer from '../../components/WriteOffDrawer' import WriteOffDrawer from '../../components/WriteOffDrawer'
import { CheckCircleOutlined } from '@ant-design/icons';
const intl = getIntl(); const intl = getIntl();
const TABLINK = [ const TABLINK = [
...@@ -147,7 +148,7 @@ const SearchDetail = () => { ...@@ -147,7 +148,7 @@ const SearchDetail = () => {
title: intl.formatMessage({ id: 'balance.businessRequestFunds.detail.columns.billNo' }), title: intl.formatMessage({ id: 'balance.businessRequestFunds.detail.columns.billNo' }),
key: 'billNo', key: 'billNo',
dataIndex: 'billNo', dataIndex: 'billNo',
render: (text: any, record: any) => <Button type='link' onClick={() => { _handleOpen(record) }} style={{padding: 0}}>{text}</Button> render: (text: any, record: any) => <Button type='link' onClick={() => { _handleOpen(record) }} style={{ padding: 0 }}>{text}</Button>
}, },
{ {
title: intl.formatMessage({ id: 'balance.businessRequestFunds.detail.columns.billAbstract' }), title: intl.formatMessage({ id: 'balance.businessRequestFunds.detail.columns.billAbstract' }),
...@@ -236,6 +237,14 @@ const SearchDetail = () => { ...@@ -236,6 +237,14 @@ const SearchDetail = () => {
no={dataSource?.applyNo} no={dataSource?.applyNo}
detail={dataSource?.applyAbstract} detail={dataSource?.applyAbstract}
tabLink={_tabs} tabLink={_tabs}
effect={
<>
{path === 'detail'
&& (
<Button icon={<CheckCircleOutlined />} type='primary'>{intl.formatMessage({ id: 'dealAbility.danjushenhe', defaultMessage: '单据审核' })}</Button>
)}
</>
}
components={ components={
<Fragment> <Fragment>
<CommonLayout layoutId="basicLayout" title={intl.formatMessage({ id: 'balance.jibenxinxi' })} effect={basicEffect} commonSpan={12} /> <CommonLayout layoutId="basicLayout" title={intl.formatMessage({ id: 'balance.jibenxinxi' })} effect={basicEffect} commonSpan={12} />
......
import React, { useRef } from 'react';
import Table from '@/components/TableLayout';
import { Tag, Badge, Button } from 'antd';
import { ColumnType } from 'antd/lib/table/interface';
import moment from 'moment';
import { INTERNALSTATE_COLOR } from '@/pages/transaction/components/stateColor';
import { getIntl } from 'umi';
import { AuthUrl } from '@/components/AuthButton/AuthUrl';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { applyAbstract, applyAmount, applyNo, applyType, createTime, expectPayTime, interiorStateName, operation, payee } from '../columns';
import { schema } from '../sechma';
const intl = getIntl();
const One = () => {
const format = (text, fmt?: string) => {
return <>{moment(text).format(fmt || "YYYY-MM-DD HH:mm:ss")}</>
}
const mock = [
{
id: 1,
applyNo: 'QPTY12',
applyAbstract: '进口头层黄牛皮荔枝纹',
applyType: '询价采购',
payee: '广州麦多食品有限公司',
applyAmount: '10,000.00',
expectPayTime: 1650614083779,
createTime: 1650614111890,
interiorStateName: '待审核请款单(一级)',
interiorState: 1,
}
]
const columns: ColumnType<any>[] = [
{
...applyNo,
render: (_text) => <a href='#'>{_text}</a>
},
{
...applyAbstract
},
{
...applyType,
},
{
...payee,
},
{
...applyAmount,
render: (_text) => ${_text}`,
},
{
...expectPayTime,
render: (_text) => format(_text, 'YYYY-MM-DD'),
},
{
...createTime,
render: (_text) => format(_text, 'YYYY-MM-DD HH:mm'),
},
{
...interiorStateName,
render: (_text, _record) => <Tag color={INTERNALSTATE_COLOR[_record.interiorState]}>{_text}</Tag>
},
{
...operation,
render: (_text, _record) => <Button type='link'>审核</Button>,
},
]
return (
<Table
columns={columns}
effects="applyNo"
fetch={mock}
schema={schema}
/>
)
}
export default One
import { ISchema } from "@formily/antd";
import { FORM_FILTER_PATH } from "@/formSchema/const";
import { getIntl } from 'umi';
export const schema: ISchema = {
type: "object",
properties: {
megalayout: {
type: "object",
"x-component": "mega-layout",
properties: {
applyNo: {
type: "string",
"x-component": "Search",
"x-mega-props": {},
"x-component-props": {
placeholder: getIntl().formatMessage({ id: 'balance.components.writeOffDrawer.columns.applyNo', defaultMessage: '请款单号' }),
align: "flex-left",
}
}
}
},
[FORM_FILTER_PATH]: {
type: "object",
"x-component": "flex-layout",
"x-component-props": {
rowStyle: {
justifyContent: "flex-start",
flexWrap: "nowrap"
},
colStyle: {//改变间隔
marginRight: 20
}
},
properties: {
PRO_LAYOUT: {
type: "object",
"x-component": "mega-layout",
"x-mega-props": {
span: 5
},
"x-component-props": {
inline: true
},
properties: {
applyAbstract: {
type: "string",
"x-component-props": {
placeholder: getIntl().formatMessage({ id: 'balance.businessRequestFundsCollaboration.detail.col.applyAbstract', defaultMessage: '请款摘要' })
}
},
payee: {
type: "string",
"x-component-props": {
placeholder: getIntl().formatMessage({ id: 'balance.businessRequestFundsCollaboration.detail.col.payee', defaultMessage: '收款方' })
}
},
"[createTimeStart,createTimeEnd]": {
type: "string",
"x-component": "DateRangePickerUnix",
"x-component-props": {
placeholder: ['单据时间开始', '单据时间结束'],
fmt: 'YYYY-MM-DD'
}
},
"[expectPayTimeStart,expectPayTimeEnd]": {
type: "string",
"x-component": "DateRangePickerUnix",
"x-component-props": {
placeholder: ['预计付款日期开始', '预计付款日期结束'],
fmt: 'YYYY-MM-DD HH:mm'
}
},
}
},
sumbit: {
"x-component": "Submit",
"x-mega-props": {
span: 1
},
"x-component-props": {
children: getIntl().formatMessage({ id: 'dealAbility.chaxun' })
}
}
}
}
}
}
import React, { useRef } from 'react';
import Table from '@/components/TableLayout';
import { Tag, Badge, Button } from 'antd';
import { ColumnType } from 'antd/lib/table/interface';
import moment from 'moment';
import { INTERNALSTATE_COLOR } from '@/pages/transaction/components/stateColor';
import { getIntl } from 'umi';
import { AuthUrl } from '@/components/AuthButton/AuthUrl';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { applyAbstract, applyAmount, applyNo, applyType, createTime, expectPayTime, interiorStateName, operation, payee } from '../columns';
import { schema } from '../sechma';
const intl = getIntl();
const Submit = () => {
const format = (text, fmt?: string) => {
return <>{moment(text).format(fmt || "YYYY-MM-DD HH:mm:ss")}</>
}
const mock = [
{
id: 1,
applyNo: 'QPTY12',
applyAbstract: '进口头层黄牛皮荔枝纹',
applyType: '询价采购',
payee: '广州麦多食品有限公司',
applyAmount: '10,000.00',
expectPayTime: 1650614083779,
createTime: 1650614111890,
interiorStateName: '待审核请款单(一级)',
interiorState: 1,
}
]
const columns: ColumnType<any>[] = [
{
...applyNo,
render: (_text) => <a href='#'>{_text}</a>
},
{
...applyAbstract
},
{
...applyType,
},
{
...payee,
},
{
...applyAmount,
render: (_text) => ${_text}`,
},
{
...expectPayTime,
render: (_text) => format(_text, 'YYYY-MM-DD'),
},
{
...createTime,
render: (_text) => format(_text, 'YYYY-MM-DD HH:mm'),
},
{
...interiorStateName,
render: (_text, _record) => <Tag color={INTERNALSTATE_COLOR[_record.interiorState]}>{_text}</Tag>
},
{
...operation,
render: (_text, _record) => <Button type='link'>审核</Button>,
},
]
return (
<Table
columns={columns}
effects="applyNo"
fetch={mock}
schema={schema}
/>
)
}
export default Submit
import React, { useRef } from 'react';
import Table from '@/components/TableLayout';
import { Tag, Badge, Button } from 'antd';
import { ColumnType } from 'antd/lib/table/interface';
import moment from 'moment';
import { INTERNALSTATE_COLOR } from '@/pages/transaction/components/stateColor';
import { getIntl } from 'umi';
import { AuthUrl } from '@/components/AuthButton/AuthUrl';
import { FORM_FILTER_PATH } from '@/formSchema/const';
import { applyAbstract, applyAmount, applyNo, applyType, createTime, expectPayTime, interiorStateName, operation, payee } from '../columns';
import { schema } from '../sechma';
const intl = getIntl();
const Two = () => {
const format = (text, fmt?: string) => {
return <>{moment(text).format(fmt || "YYYY-MM-DD HH:mm:ss")}</>
}
const mock = [
{
id: 1,
applyNo: 'QPTY12',
applyAbstract: '进口头层黄牛皮荔枝纹',
applyType: '询价采购',
payee: '广州麦多食品有限公司',
applyAmount: '10,000.00',
expectPayTime: 1650614083779,
createTime: 1650614111890,
interiorStateName: '待审核请款单(一级)',
interiorState: 1,
}
]
const columns: ColumnType<any>[] = [
{
...applyNo,
render: (_text) => <a href='#'>{_text}</a>
},
{
...applyAbstract
},
{
...applyType,
},
{
...payee,
},
{
...applyAmount,
render: (_text) => ${_text}`,
},
{
...expectPayTime,
render: (_text) => format(_text, 'YYYY-MM-DD'),
},
{
...createTime,
render: (_text) => format(_text, 'YYYY-MM-DD HH:mm'),
},
{
...interiorStateName,
render: (_text, _record) => <Tag color={INTERNALSTATE_COLOR[_record.interiorState]}>{_text}</Tag>
},
{
...operation,
render: (_text, _record) => <Button type='link'>审核</Button>,
},
]
return (
<Table
columns={columns}
effects="applyNo"
fetch={mock}
schema={schema}
/>
)
}
export default Two
...@@ -49,3 +49,19 @@ export const fetchOptions = (service) => { ...@@ -49,3 +49,19 @@ export const fetchOptions = (service) => {
return []; return [];
} }
} }
/**
* 获取结算状态
*/
export const fetchInvoiceOptions = (service) => {
return async function() {
const res = await service();
if(res.code === 1000) {
const list: any[] = res.data || []
const lastItem = list.pop()
const newList = [lastItem, ...list]
return newList.map((item) => {return { label: item.name, value: item.code.toString() }})
}
return [];
}
}
...@@ -15,12 +15,12 @@ import { schema } from './schema'; ...@@ -15,12 +15,12 @@ import { schema } from './schema';
// import InvoiceCreate from '../../components/InvoiceCreate' // import InvoiceCreate from '../../components/InvoiceCreate'
// import StatusTag from '../../components/StatusTag'; // import StatusTag from '../../components/StatusTag';
import StatusTag, { STATUS_TYPE } from '@/components/StatusTag'; import StatusTag, { STATUS_TYPE } from '@/components/StatusTag';
import { fetchOptions } from '../../../common'; import { fetchInvoiceOptions } from '../../../common';
import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable'; import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable';
import { numFormat, priceFormat } from '@/utils/numberFomat'; import { numFormat, priceFormat } from '@/utils/numberFomat';
import { import {
getSettleAccountsCommonGetReceiptInvoiceStatus, getSettleAccountsMemberSettlementAccountStatementInvoiceListStatus,
getSettleAccountsMemberSettlementPageReceiptInvoice, getSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceList,
} from '@/services/SettleV2Api'; } from '@/services/SettleV2Api';
import AuthButton from '@/components/AuthButton'; import AuthButton from '@/components/AuthButton';
import './index.less'; import './index.less';
...@@ -33,18 +33,17 @@ const InvoiceInquire: React.FC = () => { ...@@ -33,18 +33,17 @@ const InvoiceInquire: React.FC = () => {
const intl = useIntl(); const intl = useIntl();
const ref = useRef<any>({}); const ref = useRef<any>({});
const { searchData, formatInitialValue } = useSetSearchValueInTable(); const { searchData, formatInitialValue } = useSetSearchValueInTable();
/** /**
* 获取开票管理列表
* @param params * @param params
*/ */
const fetchListData = async params => { const fetchListData = async params => {
const searchParams = { const searchParams = {
...params, ...params,
invoiceStatus: params?.invoiceStatus || 2,
payStatus: params?.payStatus || 2,
...searchData, ...searchData,
orderByCode: 1,
}; };
const { data } = await getSettleAccountsMemberSettlementPageReceiptInvoice( const { data } = await getSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceList(
searchParams, searchParams,
); );
return data; return data;
...@@ -232,7 +231,7 @@ const InvoiceInquire: React.FC = () => { ...@@ -232,7 +231,7 @@ const InvoiceInquire: React.FC = () => {
); );
useAsyncSelect( useAsyncSelect(
'examineStatus', 'examineStatus',
fetchOptions(getSettleAccountsCommonGetReceiptInvoiceStatus), fetchInvoiceOptions(getSettleAccountsMemberSettlementAccountStatementInvoiceListStatus),
); );
}} }}
schema={schema} schema={schema}
......
...@@ -13,12 +13,12 @@ import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilte ...@@ -13,12 +13,12 @@ import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilte
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect'; import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
import { schema } from './schema'; import { schema } from './schema';
import StatusTag, { STATUS_TYPE } from '@/components/StatusTag'; import StatusTag, { STATUS_TYPE } from '@/components/StatusTag';
import { fetchOptions } from '../../../common'; import { fetchInvoiceOptions } from '../../../common';
import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable'; import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable';
import { numFormat, priceFormat } from '@/utils/numberFomat'; import { numFormat, priceFormat } from '@/utils/numberFomat';
import { import {
getSettleAccountsCommonGetReceiptInvoiceStatus, getSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceListStatus,
getSettleAccountsMemberSettlementPageReceiptInvoice, getSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceList,
} from '@/services/SettleV2Api'; } from '@/services/SettleV2Api';
import AuthButton from '@/components/AuthButton'; import AuthButton from '@/components/AuthButton';
import './index.less'; import './index.less';
...@@ -33,17 +33,15 @@ const InvoiceJoint: React.FC = () => { ...@@ -33,17 +33,15 @@ const InvoiceJoint: React.FC = () => {
const ref = useRef<any>({}); const ref = useRef<any>({});
const { searchData, formatInitialValue } = useSetSearchValueInTable(); const { searchData, formatInitialValue } = useSetSearchValueInTable();
/** /**
* 获取开票管理列表
* @param params * @param params
*/ */
const fetchListData = async params => { const fetchListData = async params => {
const searchParams = { const searchParams = {
...params, ...params,
invoiceStatus: params?.invoiceStatus || 2,
payStatus: params?.payStatus || 2,
...searchData, ...searchData,
orderByCode: 2,
}; };
const { data } = await getSettleAccountsMemberSettlementPageReceiptInvoice( const { data } = await getSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceList(
searchParams, searchParams,
); );
return data; return data;
...@@ -231,7 +229,7 @@ const InvoiceJoint: React.FC = () => { ...@@ -231,7 +229,7 @@ const InvoiceJoint: React.FC = () => {
); );
useAsyncSelect( useAsyncSelect(
'examineStatus', 'examineStatus',
fetchOptions(getSettleAccountsCommonGetReceiptInvoiceStatus), fetchInvoiceOptions(getSettleAccountsMemberSettlementAccountStatementCoordinationInvoiceListStatus),
); );
}} }}
schema={schema} schema={schema}
......
import React, { useState } from 'react' import React, { useState } from 'react';
import { useIntl } from 'umi' import { useIntl } from 'umi';
import { Button } from 'antd' import { Button, message } from 'antd';
import { FormDetailContext } from '@/formSchema/context' import { FormDetailContext } from '@/formSchema/context';
import { useFormDetail } from '@/formSchema/effects/useFormDetail' import { useFormDetail } from '@/formSchema/effects/useFormDetail';
import FormDetailHeader from '@/components/FormDetailHeader' import FormDetailHeader from '@/components/FormDetailHeader';
import AuthButton from '@/components/AuthButton' import TableModal from '@/components/TableModal';
import { LinkOutlined, SaveOutlined } from '@ant-design/icons' import AuthButton from '@/components/AuthButton';
import { createFormActions } from '@formily/antd' import { LinkOutlined, PlusOutlined, SaveOutlined } from '@ant-design/icons';
import { increaseSchema } from './schema' import { createFormActions } from '@formily/antd';
import styles from './index.less' import { increaseSchema } from './schema';
import FormDetailWrapper from '@/components/FormDetailWrapper' import styles from './index.less';
import NiceForm from '@/components/NiceForm' import FormDetailWrapper from '@/components/FormDetailWrapper';
import {
const addSchemaAction = createFormActions() getSettleAccountsMemberSettlementAccountStatementAddPageInvoicingProcess,
getSettleAccountsMemberSettlementAccountStatementInvoiceReconciliationRows,
getSettleAccountsMemberSettlementPageInvoicingProcessList,
getSettleAccountsMemberSettlementAccountStatementDetail,
} from '@/services/SettleV2Api'
import NiceForm from '@/components/NiceForm';
import { reconciliationColumn } from './contants'
import { InvoiceDetailType } from './types';
const addSchemaAction = createFormActions();
const AddInvoice: React.FC = () => { const AddInvoice: React.FC = () => {
const intl = useIntl() const intl = useIntl();
const [btnLoading, setBtnLoading] = useState(false) const [btnLoading, setBtnLoading] = useState(false);
const [formLoading, setFormLoading] = useState(false) const [formLoading, setFormLoading] = useState(false);
const { formContext } = useFormDetail() const { formContext } = useFormDetail();
const [initFormValue, setInitFormValue] = useState<any>({}) const [initFormValue, setInitFormValue] = useState<any>({});
const [invoiceDrawerVisible, setInvoiceDrawerVisible] = useState<boolean>(false); // 选择单据
const [statementsDrawerVisible, setStatementsDrawerVisible] = useState<boolean>(false); // 选择对账单抽屉
const [reconciliation, setReconciliation] = useState<InvoiceDetailType>()
const [invoiceDetail, setInvoiceDetail] = useState<InvoiceDetailType>()
const providerValue = { const providerValue = {
schemaActions: addSchemaAction, schemaActions: addSchemaAction,
formContext, formContext,
};
const handleSelectNo = () => {};
/**
* 获取发票详情
*/
const fetchInvoiceDetail = async (reconciliationId?: number): Promise<InvoiceDetailType | undefined> => {
const params: { reconciliationId?: number, id?: number} = {}
if (reconciliationId) {
params.reconciliationId = reconciliationId
}
const res = await getSettleAccountsMemberSettlementAccountStatementDetail(params)
if (res.code === 1000 && res.data) {
return res.data as InvoiceDetailType
}
return undefined
}
const handleSelectReconciliationClick = () => {
setInvoiceDrawerVisible(true)
}
// 选择单据号按钮
const SelectNoBtn = (
<Button type="primary" className={styles.select_btn} onClick={handleSelectReconciliationClick}>
<LinkOutlined className={styles.select_icon} />
</Button>
);
const handleSelectStatementsClick = () => {
const reconciliationNo = addSchemaAction.getFieldValue('reconciliationNo')
if (reconciliationNo) {
setStatementsDrawerVisible(true)
} else {
message.info('请先选择单据')
}
}
// 选择对账单按钮
const SelectStatementsButton = (
<div className={styles.select_statements_button} onClick={() => handleSelectStatementsClick()}>
<PlusOutlined className={styles.select_statements_button_icon} />
<span>选择对账单</span>
</div>
);
const handleStatementsModalConfirm = (selectRow: number[] | string[], selectedRows: { [key: string]: any }[]) => {
} }
const handleSelectNo = () => { const handleStatementsModalClose = () => {
setStatementsDrawerVisible(false)
}
const handleReconciliationModalConfirm = async (_: number[] | string[], selectedRows: { [key: string]: any }[]) => {
const selectedItem = selectedRows[0]
const detailInfo = await fetchInvoiceDetail(selectedItem.reconciliationId)
if (detailInfo) {
setReconciliation(detailInfo)
// 设置表单数据
Object.keys(detailInfo).forEach((key) => {
addSchemaAction.setFieldValue(key, detailInfo[key])
})
setInvoiceDrawerVisible(false)
} else {
message.info('请选择单据')
}
}
const handleReconciliationModalClose = () => {
setInvoiceDrawerVisible(false)
} }
const SelectNoBtn = <Button type='primary'><LinkOutlined /></Button> /**
* 查询待开票和开票中单据数据
* @param params
*/
const fetchReconciliationData = async (params) => {
const searchParams = {
...params,
};
const { data } = await getSettleAccountsMemberSettlementAccountStatementAddPageInvoicingProcess(
searchParams,
);
return data;
}
// const SelectNoBtn = <div className='connectBtn' onClick={handleSelectNo}><LinkOutlined style={{ marginRight: 4 }} /></div> /**
* 查询对账单数据
* @param params
*/
const fetchStatementsData = async (params) => {
const searchParams = {
...params,
reconciliationId: addSchemaAction.getFieldValue('reconciliationId'),
reconciliationNo: addSchemaAction.getFieldValue('reconciliationNo')
};
const { data } = await getSettleAccountsMemberSettlementAccountStatementInvoiceReconciliationRows(
searchParams,
);
return data;
}
return ( return (
<div className={styles['mian']}> <div className={styles['mian']}>
<FormDetailContext.Provider value={providerValue}> <FormDetailContext.Provider value={providerValue}>
<FormDetailHeader <FormDetailHeader
title={intl.formatMessage({ id: 'balance.invoice.add.page.title', defaultMessage: '新增开票' })} title={intl.formatMessage({
id: 'balance.invoice.add.page.title',
defaultMessage: '新增开票',
})}
schema={increaseSchema} schema={increaseSchema}
extraRight={[ extraRight={[
<AuthButton btnCode='invoice.manage.add'> <AuthButton btnCode="invoice.manage.add">
<Button key="1" onClick={() => addSchemaAction.submit()} loading={btnLoading} type="primary" icon={<SaveOutlined />}> <Button
{intl.formatMessage({ id: 'common.button.save', defaultMessage: '保存' })} key="1"
onClick={() => addSchemaAction.submit()}
loading={btnLoading}
type="primary"
icon={<SaveOutlined />}
>
{intl.formatMessage({
id: 'common.button.save',
defaultMessage: '保存',
})}
</Button> </Button>
</AuthButton> </AuthButton>,
]} ]}
/> />
<FormDetailWrapper> <FormDetailWrapper>
<div className={styles.restContainer}> <div className={styles.restContainer}>
<NiceForm <NiceForm
loading={formLoading} loading={formLoading}
previewPlaceholder=' ' previewPlaceholder=" "
value={initFormValue} value={initFormValue}
actions={addSchemaAction} actions={addSchemaAction}
schema={increaseSchema} schema={increaseSchema}
// onSubmit={handleSubmit} // onSubmit={handleSubmit}
components={{ components={{}}
}} effects={($, ctx) => {}}
effects={($, ctx) => {
}}
expressionScope={{ expressionScope={{
SelectNoBtn, SelectNoBtn,
SelectStatementsButton,
}} }}
/> />
<TableModal
title="选择单据"
modalType="Drawer"
visible={invoiceDrawerVisible}
schema={{}}
tableProps={{
rowKey: 'reconciliationNo',
}}
columns={reconciliationColumn}
mode='radio'
fetchData={fetchReconciliationData}
onClose={handleReconciliationModalClose}
onOk={handleReconciliationModalConfirm}
/>
<TableModal
title="选择对账单"
modalType="Drawer"
visible={statementsDrawerVisible}
schema={{}}
columns={[]}
mode='checkbox'
fetchData={fetchStatementsData}
onClose={handleStatementsModalClose}
onOk={handleStatementsModalConfirm}
/>
</div> </div>
</FormDetailWrapper> </FormDetailWrapper>
</FormDetailContext.Provider> </FormDetailContext.Provider>
</div> </div>
) );
} };
export default AddInvoice export default AddInvoice;
import { priceFormat } from '@/utils/numberFomat';
import { getIntl } from 'umi'
const intl = getIntl()
export const reconciliationColumn = [
{
title: intl.formatMessage({
id: 'balance.common.columns.productNoticecolumns.orderNo',
}),
dataIndex: 'reconciliationNo',
},
{
title: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.orderAbstract',
}),
dataIndex: 'reconciliationAbstract',
},
{
title: intl.formatMessage({
id:
'balance.accountsReceivable.invoice.columns.settlementOrderTypeName',
}),
dataIndex: 'reconciliationTypeName',
},
{
title: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.orderTime',
}),
dataIndex: 'createTime',
},
{
title: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.tax',
}),
dataIndex: 'tax',
render: (_, record) => {
return record.isTaxRate === 1
? `${intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.tax.yes',
})}/${priceFormat(record.taxRate * 100)}%`
: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.tax.none',
});
},
},
{
title: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.orderAmount',
}),
dataIndex: 'reconciliationMoneyAmount',
render: (text) =>
`${intl.formatMessage({ id: 'common.money' })} ${priceFormat(text)}`,
},
{
title: intl.formatMessage({
id: 'balance.accountsReceivable.invoice.columns.invoiceStatus',
}),
dataIndex: 'invoiceStatusName',
},
]
...@@ -10,10 +10,47 @@ ...@@ -10,10 +10,47 @@
.restContainer { .restContainer {
margin-top: 16px; margin-top: 16px;
.select_btn {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
.select_icon {
width: 16px;
height: 16px;
}
}
.select_statements_button {
display: flex;
height: 32px;
background-color: #FAFBFC;
border-radius: 4px;
border: 1px dashed #EDEEEF;
margin-bottom: 16px;
align-items: center;
justify-content: center;
color: #5C626A;
font-size: 12px;
cursor: pointer;
&_icon {
margin-right: 8px;
font-size: 14px;
}
}
:global { :global {
.ant-card-head {
margin-bottom: 8px;
}
.ant-card-body { .ant-card-body {
padding-top: 0!important; padding-top: 0!important;
padding-bottom: 0!important;
} }
.ant-card { .ant-card {
...@@ -34,16 +71,16 @@ ...@@ -34,16 +71,16 @@
.ant-input { .ant-input {
border: 1px solid #f4f6f8 !important; border: 1px solid #f4f6f8 !important;
&.ant-input-status-error {
border: none;
box-shadow: none;
&:focus, &:active { &:focus, &:active {
border: none; border: none;
box-shadow: none; box-shadow: none;
} }
} }
.ant-input-status-error {
border: none;
box-shadow: none;
&:focus, &:active { &:focus, &:active {
border: none; border: none;
box-shadow: none; box-shadow: none;
......
...@@ -17,8 +17,7 @@ import { fetchOptions } from '../../../common'; ...@@ -17,8 +17,7 @@ import { fetchOptions } from '../../../common';
import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable'; import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable';
import { priceFormat } from '@/utils/numberFomat'; import { priceFormat } from '@/utils/numberFomat';
import { import {
getSettleAccountsCommonGetReceiptInvoiceStatus, getSettleAccountsMemberSettlementAccountStatementInvoiceList,
getSettleAccountsMemberSettlementPageReceiptInvoice,
} from '@/services/SettleV2Api'; } from '@/services/SettleV2Api';
import AuthButton from '@/components/AuthButton'; import AuthButton from '@/components/AuthButton';
import './index.less'; import './index.less';
...@@ -33,17 +32,15 @@ const InvoiceManage: React.FC = () => { ...@@ -33,17 +32,15 @@ const InvoiceManage: React.FC = () => {
const ref = useRef<any>({}); const ref = useRef<any>({});
const { searchData, formatInitialValue } = useSetSearchValueInTable(); const { searchData, formatInitialValue } = useSetSearchValueInTable();
/** /**
* 获取开票管理列表
* @param params * @param params
*/ */
const fetchListData = async params => { const fetchListData = async params => {
const searchParams = { const searchParams = {
...params, ...params,
invoiceStatus: params?.invoiceStatus || 2,
payStatus: params?.payStatus || 2,
...searchData, ...searchData,
orderByCode: 1,
}; };
const { data } = await getSettleAccountsMemberSettlementPageReceiptInvoice( const { data } = await getSettleAccountsMemberSettlementAccountStatementInvoiceList(
searchParams, searchParams,
); );
return data; return data;
...@@ -249,10 +246,6 @@ const InvoiceManage: React.FC = () => { ...@@ -249,10 +246,6 @@ const InvoiceManage: React.FC = () => {
'megaLayout.reconciliationNo', 'megaLayout.reconciliationNo',
FORM_FILTER_PATH, FORM_FILTER_PATH,
); );
useAsyncSelect(
'examineStatus',
fetchOptions(getSettleAccountsCommonGetReceiptInvoiceStatus),
);
}} }}
schema={schema} schema={schema}
onSubmit={handleSearch} onSubmit={handleSearch}
......
...@@ -69,14 +69,6 @@ export const schema: ISchema = { ...@@ -69,14 +69,6 @@ export const schema: ISchema = {
} }
}, },
}, },
examineStatus: {
type: 'string',
enum: [],
'x-component-props': {
placeholder: intl.formatMessage({ id: 'balance.accountsReceivable.invoice.schema.invoiceStatus' }),
allowClear: true,
},
},
submit: { submit: {
'x-component': 'Submit', 'x-component': 'Submit',
'x-mega-props': { 'x-mega-props': {
...@@ -114,24 +106,57 @@ const receiptInfo: ISchema = { ...@@ -114,24 +106,57 @@ const receiptInfo: ISchema = {
columns: 2, columns: 2,
}, },
properties: { properties: {
// 单据号 reconciliationId: {
type: 'string',
readOnly: true,
visible: false,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.reconciliationId', defaultMessage: '对账单ID' }),
},
reconciliationNo: { reconciliationNo: {
type: 'string', type: 'string',
title: intl.formatMessage({ id: 'balance.common.columns.productNoticecolumns.orderNo' }), title: intl.formatMessage({ id: 'balance.common.columns.productNoticecolumns.orderNo' }),
"x-component-props": { "x-component-props": {
addonAfter: "{{SelectNoBtn}}" addonAfter: "{{SelectNoBtn}}",
disabled: true,
}, },
"x-rules": [ "x-rules": [
{ {
required: true, required: true,
message: getIntl().formatMessage({ id: 'balance.invoice.reconciliationNo.required', defaultMessage: '请选择单据号' }) message: getIntl().formatMessage({ id: 'balance.invoice.reconciliationNo.required', defaultMessage: '请选择单据号' }),
} }
], ],
}, },
payer: { payer: {
type: 'string', type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.payer', defaultMessage: '付款方' }), title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.payer', defaultMessage: '付款方' }),
}, },
reconciliationAbstract: {
type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.reconciliationAbstract', defaultMessage: '单据摘要' }),
},
createTime: {
type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.createTime', defaultMessage: '单据时间' }),
},
reconciliationTypeName: {
type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.reconciliationType', defaultMessage: '单据类型' }),
},
reconciliationType: {
type: 'string',
readOnly: true,
visible: false,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.reconciliationType', defaultMessage: '单据类型' }),
},
returnResource: {
type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.returnResource', defaultMessage: '退回原因' }),
},
}, },
} }
} }
...@@ -160,7 +185,46 @@ const invoiceInfo: ISchema = { ...@@ -160,7 +185,46 @@ const invoiceInfo: ISchema = {
columns: 2, columns: 2,
}, },
properties: { properties: {
type: {
type: 'string',
readOnly: true,
title: intl.formatMessage({ id: 'balance.common.columns.productNoticecolumns.type', defaultMessage: '开具类型' }),
},
bankOfDeposit: {
type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.bankOfDeposit', defaultMessage: '开户行' }),
},
kind: {
type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.kind', defaultMessage: '发票种类' }),
},
account: {
type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.account', defaultMessage: '账号' }),
},
invoiceTitle: {
type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.invoiceTitle', defaultMessage: '发票抬头' }),
},
address: {
type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.address', defaultMessage: '地址' }),
},
taxNo: {
type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.taxNo', defaultMessage: '纳税号' }),
},
tel: {
type: 'string',
readOnly: true,
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.tel', defaultMessage: '电话号码' }),
},
}, },
} }
} }
...@@ -175,6 +239,80 @@ const billInfo: ISchema = { ...@@ -175,6 +239,80 @@ const billInfo: ISchema = {
title: getIntl().formatMessage({ id: 'balance.invoice.manage.addSchema.billInfo', defaultMessage: '开票信息' }), title: getIntl().formatMessage({ id: 'balance.invoice.manage.addSchema.billInfo', defaultMessage: '开票信息' }),
id: 'billInfo', id: 'billInfo',
}, },
properties: {
NO_SUBMIT_LAYOUT: {
type: 'object',
"x-component": 'mega-layout',
"x-component-props": {
labelCol: 6,
wrapperCol: 16,
labelAlign: "left",
grid: true,
full: true,
autoRow: true,
columns: 2,
},
properties: {
code: {
type: 'string',
title: intl.formatMessage({ id: 'balance.common.columns.productNoticecolumns.code', defaultMessage: '发票代码' }),
"x-component-props": {
placeholder: '最长20个字符',
},
"x-rules": [
{
required: true,
message: getIntl().formatMessage({ id: 'balance.invoice.reconciliationNo.required', defaultMessage: '请输入发票代码' }),
},
{
limitByte: true,
maxByte: 20,
message: '最长20个字符'
}
],
},
invoiceDate: {
type: 'string',
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.invoiceDate', defaultMessage: '开票日期' }),
"x-rules": [
{
required: true,
message: getIntl().formatMessage({ id: 'balance.invoice.reconciliationNo.required', defaultMessage: '请选择开票日期' }),
},
{
limitByte: true,
maxByte: 20,
message: '最长20个字符'
}
],
},
number: {
type: 'string',
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.number', defaultMessage: '发票号码' }),
"x-component-props": {
placeholder: '最长20个字符'
},
"x-rules": [
{
required: true,
message: getIntl().formatMessage({ id: 'balance.invoice.reconciliationNo.required', defaultMessage: '请输入发票号码' }),
}
],
},
remark: {
type: 'string',
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.remark', defaultMessage: '备注' }),
"x-component-props": {
placeholder: '最长100个文字',
}
},
urlImgs: {
type: 'string',
title: getIntl().formatMessage({ id: 'balance.accountsReceivable.invoice.columns.urlImgs', defaultMessage: '发票图片' }),
},
},
}
}
} }
// 发票明细 // 发票明细
...@@ -186,6 +324,19 @@ const invoiceDetails: ISchema = { ...@@ -186,6 +324,19 @@ const invoiceDetails: ISchema = {
title: getIntl().formatMessage({ id: 'balance.invoice.manage.addSchema.invoiceDetails', defaultMessage: '发票明细' }), title: getIntl().formatMessage({ id: 'balance.invoice.manage.addSchema.invoiceDetails', defaultMessage: '发票明细' }),
id: 'invoiceDetails', id: 'invoiceDetails',
}, },
properties: {
rows: {
type: 'array',
"x-component": 'MultTable',
required: true,
"x-component-props": {
rowKey: 'id',
// columns: "{{productColumns}}",
// components: "{{productComponents}}",
prefix: "{{SelectStatementsButton}}",
},
},
}
} }
export const increaseSchema: ISchema = { export const increaseSchema: ISchema = {
......
export interface InvoiceDetailType {
/**
* 开票id
*/
id: number
/**
* 对账单id
*/
reconciliationId: number
/**
* 对账单号
*/
reconciliationNo: string
/**
* 对账单摘要
*/
reconciliationAbstract: string
/**
* 对账单类型
*/
reconciliationType: number
/**
* 对账单类型名称
*/
reconciliationTypeName: string
/**
* 单据时间
*/
createTime: string
/**
* 付款方
*/
payer: string
/**
* 发票种类:1.增值税普通发票(默认)2.增值税专用发票
*/
kind: number
/**
* 发票类型:1.企业(默认)2.个人
*/
type: number
/**
* 发票抬头
*/
invoiceTitle: string
/**
* 纳税号
*/
taxNo: string
/**
* 开户行
*/
bankOfDeposit: string
/**
* 账号
*/
account: string
/**
* 地址
*/
address: string
/**
* 电话
*/
tel: string
/**
* 发票号码
*/
number: string
/**
* 发票代码
*/
code: string
/**
* 开票日期
*/
invoiceDate: string
/**
* 备注
*/
remark: string
/**
* 发票图片 ,String
*/
urlImgs: string[]
/**
* 退回原因
*/
returnResource: string
}
...@@ -13,13 +13,13 @@ import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilte ...@@ -13,13 +13,13 @@ import { useStateFilterSearchLinkageEffect } from '@/formSchema/effects/useFilte
import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect'; import { useAsyncSelect } from '@/formSchema/effects/useAsyncSelect';
import { schema } from './schema'; import { schema } from './schema';
import StatusTag from '@/components/StatusTag'; import StatusTag from '@/components/StatusTag';
import { fetchOptions } from '../../../common'; import { fetchInvoiceOptions } from '../../../common';
import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable'; import useSetSearchValueInTable from '@/hooks/useSetSearchValueInTable';
import { priceFormat } from '@/utils/numberFomat'; import { priceFormat } from '@/utils/numberFomat';
import { import {
getSettleAccountsCommonGetPayStatus, getSettleAccountsMemberSettlementAccountStatementTobeInvoiceListStatus,
getSettleAccountsCommonGetReceiptInvoiceStatus, getSettleAccountsMemberSettlementPageInvoicingProcessList,
getSettleAccountsMemberSettlementPageReceiptInvoice,
} from '@/services/SettleV2Api'; } from '@/services/SettleV2Api';
import AuthButton from '@/components/AuthButton'; import AuthButton from '@/components/AuthButton';
import './index.less'; import './index.less';
...@@ -34,17 +34,14 @@ const SettlementList: React.FC = () => { ...@@ -34,17 +34,14 @@ const SettlementList: React.FC = () => {
const { searchData, formatInitialValue } = useSetSearchValueInTable(); const { searchData, formatInitialValue } = useSetSearchValueInTable();
/** /**
* 获取开票管理列表
* @param params * @param params
*/ */
const fetchListData = async params => { const fetchListData = async params => {
const searchParams = { const searchParams = {
...params, ...params,
invoiceStatus: params?.invoiceStatus || 2,
payStatus: params?.payStatus || 2,
...searchData, ...searchData,
}; };
const { data } = await getSettleAccountsMemberSettlementPageReceiptInvoice( const { data } = await getSettleAccountsMemberSettlementPageInvoicingProcessList(
searchParams, searchParams,
); );
return data; return data;
...@@ -219,19 +216,12 @@ const SettlementList: React.FC = () => { ...@@ -219,19 +216,12 @@ const SettlementList: React.FC = () => {
); );
useAsyncSelect( useAsyncSelect(
'invoiceStatus', 'invoiceStatus',
fetchOptions(getSettleAccountsCommonGetReceiptInvoiceStatus), fetchInvoiceOptions(getSettleAccountsMemberSettlementAccountStatementTobeInvoiceListStatus),
);
// 单据类型
useAsyncSelect(
'payStatus',
fetchOptions(getSettleAccountsCommonGetPayStatus),
); );
}} }}
schema={schema} schema={schema}
onSubmit={handleSearch} onSubmit={handleSearch}
onReset={() => { onReset={() => {
formActions.setFieldValue('payStartTime', null);
formActions.setFieldValue('payEndTime', null);
formActions.setFieldValue('orderStartTime', null); formActions.setFieldValue('orderStartTime', null);
formActions.setFieldValue('orderEndTime', null); formActions.setFieldValue('orderEndTime', null);
}} }}
......
...@@ -60,7 +60,7 @@ const ReceivingNoteQuery: React.FC = () => { ...@@ -60,7 +60,7 @@ const ReceivingNoteQuery: React.FC = () => {
{ title: '收货日期', dataIndex: 'receiveTime', key: 'receiveTime' }, { title: '收货日期', dataIndex: 'receiveTime', key: 'receiveTime' },
{ title: '送货单号', dataIndex: 'deliveryNo', key: 'deliveryNo' }, { title: '送货单号', dataIndex: 'deliveryNo', key: 'deliveryNo' },
{ title: '送货日期', dataIndex: 'deliveryTime', key: 'deliveryTime' }, { title: '送货日期', dataIndex: 'deliveryTime', key: 'deliveryTime' },
{ title: '采购会员', dataIndex: 'vendorMemberName', key: 'vendorMemberName' }, { title: '采购会员', dataIndex: 'buyerMemberName', key: 'buyerMemberName' },
{ title: '单据时间', dataIndex: 'createTime', key: 'createTime' }, { title: '单据时间', dataIndex: 'createTime', key: 'createTime' },
{ {
title: '外部状态', title: '外部状态',
......
...@@ -74,7 +74,7 @@ const DeliveryNoteManageDetails: React.FC = () => { ...@@ -74,7 +74,7 @@ const DeliveryNoteManageDetails: React.FC = () => {
</ListInfoItem> </ListInfoItem>
<ListInfoItem label='供应会员'> <ListInfoItem label='供应会员'>
{info?.buyerMemberName} {info?.vendorMemberName}
</ListInfoItem> </ListInfoItem>
<ListInfoItem label='收货单摘要'> <ListInfoItem label='收货单摘要'>
......
...@@ -73,7 +73,7 @@ const DeliveryNoteDetails: React.FC = () => { ...@@ -73,7 +73,7 @@ const DeliveryNoteDetails: React.FC = () => {
</ListInfoItem> </ListInfoItem>
<ListInfoItem label='供应会员'> <ListInfoItem label='供应会员'>
{info?.buyerMemberName} {info?.vendorMemberName}
</ListInfoItem> </ListInfoItem>
<ListInfoItem label='送货单摘要'> <ListInfoItem label='送货单摘要'>
......
...@@ -91,7 +91,7 @@ const DeliveryNoteQuery: React.FC = () => { ...@@ -91,7 +91,7 @@ const DeliveryNoteQuery: React.FC = () => {
}, },
{ title: '送货单摘要', dataIndex: 'digest', key: 'digest' }, { title: '送货单摘要', dataIndex: 'digest', key: 'digest' },
{ title: '送货日期', dataIndex: 'deliveryTime', key: 'deliveryTime' }, { title: '送货日期', dataIndex: 'deliveryTime', key: 'deliveryTime' },
{ title: '供应会员', dataIndex: 'vendorMemberName', key: 'vendorMemberName' }, { title: '供应会员', dataIndex: 'buyerMemberName', key: 'buyerMemberName' },
{ title: '单据时间', dataIndex: 'createTime', key: 'createTime' }, { title: '单据时间', dataIndex: 'createTime', key: 'createTime' },
{ {
title: '外部状态', title: '外部状态',
......
import { ColumnType } from 'antd/lib/table/interface';
/** 流程规则ID */
export const id: ColumnType<any> = {
title: '流程规则ID',
key: 'id',
dataIndex: 'id',
}
/** 流程规则名称 */
export const name: ColumnType<any> = {
title: '流程规则名称',
key: 'name',
dataIndex: 'name',
}
/** 流程名称 */
export const processName: ColumnType<any> = {
title: '流程名称',
key: 'processName',
dataIndex: 'processName',
}
/** 操作时间 */
export const createTime: ColumnType<any> = {
title: '操作时间',
key: 'createTime',
dataIndex: 'createTime',
}
/** 状态 */
export const status: ColumnType<any> = {
title: '状态',
key: 'status',
dataIndex: 'status',
}
/** 操作 */
export const operation: ColumnType<any> = {
title: '操作',
key: 'operation',
dataIndex: 'operation',
}
import React, { Fragment, useState } from 'react';
import PeripheralLayout from '@/pages/transaction/components/detailLayout';
import { Button, Form } from 'antd';
import { SaveOutlined } from '@ant-design/icons';
import ProcessEngLayout from './components/processEng';
import ProcessSelectLayout from './components/processSelect';
import InvoiceTypeLayout from './components/invoiceType';
export const layout: any = {
colon: false,
labelCol: { style: { width: "144px" } },
labelAlign: "left"
};
const AddInvoiceProcessEng: React.FC<{}> = () => {
const [percent, setPercent] = useState<number>(0);
/**计算输入框输入了百分之多少 */
const onValuesChange = (allValues) => {
const values = Object.values(allValues);
let num = 0;
values.forEach(_item => {
if (_item) {
num += 1
}
})
console.log(((num/values.length) * 100).toFixed(0) + '%')
}
return (
<Fragment>
<PeripheralLayout
hideBreak
detail='新增请款单流程规则'
tabLink={[
{ title: '流程规则', id: 'processEng' },
{ title: '流程选择', id: 'processSelect' },
{ title: '请款类型', id: 'invoiceType' },
]}
effect={
<Button
icon={<SaveOutlined />}
type="primary"
>
保存
</Button>
}
components={
<Form {...layout} onValuesChange={(_, allValues) => onValuesChange(allValues) }>
<ProcessEngLayout />
<ProcessSelectLayout />
<InvoiceTypeLayout />
</Form>
}
/>
</Fragment>
)
}
export default AddInvoiceProcessEng
.cardLayout {
margin-bottom: 24px;
border-radius: 8px;
background-color: #FFF;
.card_title {
padding: 12px 16px;
}
.card_title_weight {
font-size: 14px;
font-weight: 600;
}
.card_body {
padding: 16px;
}
}
import React, { CSSProperties } from 'react';
import style from './index.less';
import cx from 'classnames';
export interface cardProps {
/** 瞄点id */
id?: string,
/** 标题 */
title?: string,
/** 加粗标题 */
weight?: boolean,
/** body样式修改 */
bodyStyle?: CSSProperties,
/** calssName */
classNames?: string,
}
const CardLayout: React.FC<cardProps> = (props: any) => {
const { id, title, weight, children, bodyStyle, classNames, click } = props;
return (
<div id={id} className={cx(style.cardLayout, classNames && classNames)}>
{title && (
<div className={cx(style.card_title, weight && style.card_title_weight)}>{title}</div>
)}
<div className={style.card_body} style={bodyStyle && bodyStyle}>
{children}
</div>
</div>
)
}
export default CardLayout;
@import '../../../../../../theme/style/colors.less';
.invoice-type {
:global {
.ant-radio-wrapper {
padding: 8px 16px;
border-radius: 4px;
border: 1px solid #F5F6F7;
background-color: #F5F6F7;
margin-right: 16px;
}
.ant-radio-wrapper-checked {
border: 1px solid #00A98F;
background-color: rgba(0, 169, 143, 0.04);
span {
color: #00A98F;
}
}
}
}
import React from 'react';
import { Form, Radio } from 'antd';
import { FormInstance } from 'antd/es/form/Form';
import CardLayout from '../card';
import styles from './index.less';
interface InvoiceTypeProps {
/** FormInstance */
form?: FormInstance,
}
const InvoiceTypeLayout: React.FC<InvoiceTypeProps> = (props: any) => {
const { form } = props;
const mock = [
{value: 1, label: '物料对账单'},
{value: 2, label: '采购询价合同'},
{value: 3, label: '采购招标合同'},
{value: 4, label: '采购竞价合同'},
{value: 5, label: '请购单合同'},
{value: 6, label: '采购请购单'},
]
return (
<CardLayout
id="invoiceType"
title='请款类型'
weight
bodyStyle={{ paddingBottom: '1px' }}
classNames={styles['invoice-type']}
>
<Form.Item
name='invoiceType'
rules={[
{ required: true, message: '请选择请款类型' },
]}
>
<Radio.Group>
{mock.map(_item => (
<Radio key={_item.value} value={_item.value}>{_item.label}</Radio>
))}
</Radio.Group>
</Form.Item>
</CardLayout>
)
}
export default InvoiceTypeLayout;
import React from 'react';
import { Form, Row, Col, Input } from 'antd';
import { FormInstance } from 'antd/es/form/Form';
import CardLayout from '../card';
import { validatorByte } from '@/utils/regExp';
interface ProcessEngProps {
/** FormInstance */
form?: FormInstance,
}
const ProcessEngLayout: React.FC<ProcessEngProps> = (props: any) => {
const { form } = props;
return (
<CardLayout
id="processEng"
title='流程规则'
weight
bodyStyle={{ paddingBottom: '0px' }}
>
<Row gutter={[24, 24]}>
<Col span={12}>
<Form.Item
label='流程规则名称'
name='name'
rules={[
{ required: true, message: '请输入流程规则名称' },
{ validator: (rule, value, callback) => validatorByte(rule, value, callback, 48) }
]}
>
<Input placeholder='最长48个字符,24个汉字' />
</Form.Item>
</Col>
</Row>
</CardLayout>
)
}
export default ProcessEngLayout;
.select-box {
:global {
.ant-radio-group {
width: 100%;
.ant-radio-wrapper {
width: 100%;
padding: 16px 0px;
display: flex;
align-items: center;
border-bottom: 1px solid #F5F6F7;
.ant-radio {
width: 16px;
height: 16px;
}
span:nth-child(2) {
flex: 1;
display: inline-block;
}
}
.ant-radio-wrapper:last-child {
border-bottom: 0px;
}
}
}
.box {
display: flex;
align-items: center;
justify-content: space-between;
.box-clerk {
padding-left: 8px;
.box-clerk-name {
font-size: 14px;
color: #252D37;
font-weight: 400;
line-height: 20px;
padding: 4px 0px
}
.box-clerk-value {
font-weight: 400;
font-size: 12px;
color: #91959B;
line-height: 16px;
padding: 4px 0px
}
}
.box-tag {
padding: 4px;
border-radius: 2px;
color: #4787F0;
background-color: #ECF2FE;
}
}
}
import React from 'react';
import { Form, Radio, Space } from 'antd';
import { FormInstance } from 'antd/es/form/Form';
import CardLayout from '../card';
import styles from './index.less';
interface ProcessSelectProps {
/** FormInstance */
form?: FormInstance,
}
const ProcessSelectLayout: React.FC<ProcessSelectProps> = (props: any) => {
const { form } = props;
const mock = [
{ id: 1, name: '请款单流程--0级', value: '-', tag: '请款单流程' },
{ id: 2, name: '请款单流程--1级', value: '1-待提交请款单', tag: '请款单流程' },
{ id: 3, name: '请款单流程--2级', value: '1-待审核请款单(一级) —>2-待提交请款单', tag: '请款单流程' },
{ id: 4, name: '请款单流程--3级', value: '1-待审核请款单(一级) —>2-审核请款单(二级)—>3-待提交请款单', tag: '请款单流程' },
]
return (
<CardLayout
id="processSelect"
title='流程选择'
weight
bodyStyle={{ paddingBottom: '1px' }}
classNames={styles['select-box']}
>
<Form.Item
name='processSelect'
rules={[
{ required: true, message: '请选择流程' },
]}
>
<Radio.Group>
{mock.map(_item => (
<Radio key={_item.id} value={_item.id}>
<div className={styles['box']}>
<div className={styles['box-clerk']}>
<div className={styles['box-clerk-name']}>{_item.name}</div>
<div className={styles['box-clerk-value']}>{_item.value}</div>
</div>
<div className={styles['box-tag']}>{_item.tag}</div>
</div>
</Radio>
))}
</Radio.Group>
</Form.Item>
</CardLayout>
)
}
export default ProcessSelectLayout;
import React from 'react';
import { history, Link } from 'umi';
import { Button, Switch } from 'antd';
import moment from 'moment';
import { PlusOutlined } from '@ant-design/icons';
import TableLayout from '@/components/TableLayout';
import { ColumnType } from 'antd/lib/table/interface';
import { createTime, id, name, operation, processName, status } from '../../columns';
const InvoiceProcessEng: React.FC<{}> = () => {
const format = (text, fmt?: string) => {
return <>{moment(text).format(fmt || "YYYY-MM-DD HH:mm:ss")}</>
}
const mock = [
{
id: 1,
name: '物料对账单请款流程',
processName: '请款单流程-2级',
createTime: 1650614111890,
status: 1,
}
]
const columns: ColumnType<any>[] = [
{
...id,
},
{
...name,
render: (_text) => <Link to='#'>{_text}</Link>
},
{
...processName,
},
{
...createTime,
render: (_text) => format(_text)
},
{
...status,
render: (_text) => <Switch checked={!!_text} />
},
{
...operation,
render: (_text) => <>
<Button type='link'>编辑</Button>
<Button type='link'>删除</Button>
</>
},
]
return (
<TableLayout
columns={columns}
fetch={mock}
schema={{
type: "object",
properties: {
megalayout: {
type: "object",
"x-component": "flex-layout",
"x-component-props": {
rowStyle: {
justifyContent: 'space-between'
}
},
properties: {
ctl: {
type: "object",
"x-component": "controllerBtns",
},
name: {
type: 'string',
'x-component': 'Search',
'x-component-props': {
placeholder: '流程规则名称',
advanced: false
},
},
}
}
}
}}
controllerBtns={<Button type='primary' icon={<PlusOutlined />} onClick={() => history.push('/memberCenter/systemSetting/processEng/invoiceProcessEng/add')}>新增</Button>}
/>
)
}
export default InvoiceProcessEng;
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