kts-component-invoice-operate 3.1.2 → 3.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/.dumi/theme/builtins/API.tsx +66 -66
  2. package/.editorconfig +16 -16
  3. package/.fatherrc.ts +4 -4
  4. package/.prettierignore +7 -7
  5. package/.prettierrc +11 -11
  6. package/.umirc.ts +8 -8
  7. package/README.md +5 -5
  8. package/dist/Invoice/InvoiceController/InvoiceControllerState/GoodsListState/IGood/index.d.ts +2 -2
  9. package/dist/Invoice/ui/GoodsList/hook/useColumns/autoFillFn/index.d.ts +1 -1
  10. package/dist/index.esm.js +2715 -3859
  11. package/dist/index.js +2715 -3859
  12. package/docs/index.md +5 -5
  13. package/docs-dist/umi.js +1 -1
  14. package/index.html +12 -12
  15. package/package.json +59 -59
  16. package/src/Invoice/InvoiceController/InvoiceControllerForm/index.ts +94 -94
  17. package/src/Invoice/InvoiceController/InvoiceControllerState/BuyerState/index.tsx +88 -88
  18. package/src/Invoice/InvoiceController/InvoiceControllerState/GoodsListState/EndowCode/index.tsx +90 -90
  19. package/src/Invoice/InvoiceController/InvoiceControllerState/GoodsListState/IColumnsReplenish/index.ts +10 -10
  20. package/src/Invoice/InvoiceController/InvoiceControllerState/GoodsListState/IGood/index.ts +72 -72
  21. package/src/Invoice/InvoiceController/InvoiceControllerState/GoodsListState/ImportGoods/index.ts +80 -80
  22. package/src/Invoice/InvoiceController/InvoiceControllerState/GoodsListState/LineAttributeType/index.ts +5 -5
  23. package/src/Invoice/InvoiceController/InvoiceControllerState/GoodsListState/ProductComparison/index.ts +9 -9
  24. package/src/Invoice/InvoiceController/InvoiceControllerState/GoodsListState/index.ts +88 -88
  25. package/src/Invoice/InvoiceController/InvoiceControllerState/index.ts +42 -42
  26. package/src/Invoice/InvoiceController/fns/addGood.ts +11 -11
  27. package/src/Invoice/InvoiceController/fns/addGoodDiscount.ts +125 -125
  28. package/src/Invoice/InvoiceController/fns/delGood.ts +43 -43
  29. package/src/Invoice/InvoiceController/fns/getGoodsSearch.ts +23 -23
  30. package/src/Invoice/InvoiceController/fns/saveEditGood.ts +23 -23
  31. package/src/Invoice/InvoiceController/fns/setEditGood.ts +16 -16
  32. package/src/Invoice/InvoiceController/fns/setGoods.ts +10 -10
  33. package/src/Invoice/InvoiceController/fns/updateInvoiceNo.ts +8 -8
  34. package/src/Invoice/InvoiceController/index.ts +61 -61
  35. package/src/Invoice/_test/buyerNameSearch/index.tsx +41 -41
  36. package/src/Invoice/_test/deduction/index.tsx +935 -935
  37. package/src/Invoice/_test/draft/index.tsx +40 -40
  38. package/src/Invoice/_test/easiest/index.tsx +5 -5
  39. package/src/Invoice/_test/endowCode/index.tsx +1095 -1095
  40. package/src/Invoice/_test/goodsMenuExpand/index.tsx +32 -32
  41. package/src/Invoice/_test/importBuyer/index.tsx +74 -74
  42. package/src/Invoice/_test/importGoods/index.tsx +515 -515
  43. package/src/Invoice/_test/invoiceType/index.tsx +59 -59
  44. package/src/Invoice/_test/isInvoiceNo/index.tsx +12 -12
  45. package/src/Invoice/_test/replaceHead/index.tsx +22 -22
  46. package/src/Invoice/_test/retrieveData/index.tsx +22 -22
  47. package/src/Invoice/_test/seller/index.tsx +28 -28
  48. package/src/Invoice/_test/setDataSource/index.tsx +22 -22
  49. package/src/Invoice/_test/unit/index.tsx +19 -19
  50. package/src/Invoice/index.less +12 -12
  51. package/src/Invoice/index.md +53 -53
  52. package/src/Invoice/index.tsx +104 -104
  53. package/src/Invoice/tools/calculate/index.ts +97 -97
  54. package/src/Invoice/tools/coolingFn/index.ts +17 -17
  55. package/src/Invoice/tools/evaluate/index.ts +7 -7
  56. package/src/Invoice/tools/idGenerator/index.ts +2 -2
  57. package/src/Invoice/tools/itemName/index.ts +46 -46
  58. package/src/Invoice/tools/lazyFn/index.ts +19 -19
  59. package/src/Invoice/tools/strringFn/index.ts +40 -40
  60. package/src/Invoice/ui/AddComparisonDrawer/index.tsx +149 -149
  61. package/src/Invoice/ui/Buyer/index.less +219 -219
  62. package/src/Invoice/ui/Buyer/index.tsx +114 -114
  63. package/src/Invoice/ui/Buyer/ui/BuyerNameInput/index.tsx +166 -166
  64. package/src/Invoice/ui/Buyer/ui/ImportBuyerButton/index.tsx +21 -21
  65. package/src/Invoice/ui/EndowCodeDrawer/index.less +8 -8
  66. package/src/Invoice/ui/EndowCodeDrawer/index.tsx +441 -441
  67. package/src/Invoice/ui/GoodsList/hook/useColumns/autoFillFn/index.ts +490 -490
  68. package/src/Invoice/ui/GoodsList/hook/useColumns/index.tsx +603 -603
  69. package/src/Invoice/ui/GoodsList/hook/useColumns/ui/ItemNameInput/index.less +9 -9
  70. package/src/Invoice/ui/GoodsList/hook/useColumns/ui/ItemNameInput/index.tsx +34 -34
  71. package/src/Invoice/ui/GoodsList/hook/useColumns/ui/RowEditButton/index.tsx +30 -30
  72. package/src/Invoice/ui/GoodsList/hook/useColumns/ui/RowMenu/hook/_useAddComparison/index.tsx +43 -43
  73. package/src/Invoice/ui/GoodsList/hook/useColumns/ui/RowMenu/hook/useAddDiscount/index.tsx +76 -76
  74. package/src/Invoice/ui/GoodsList/hook/useColumns/ui/RowMenu/hook/useDelItem/index.tsx +35 -35
  75. package/src/Invoice/ui/GoodsList/hook/useColumns/ui/RowMenu/hook/useEndowCode/index.tsx +34 -34
  76. package/src/Invoice/ui/GoodsList/hook/useColumns/ui/RowMenu/index.less +13 -13
  77. package/src/Invoice/ui/GoodsList/hook/useColumns/ui/RowMenu/index.tsx +98 -98
  78. package/src/Invoice/ui/GoodsList/hook/useColumns/ui/RowSaveButton/index.tsx +14 -14
  79. package/src/Invoice/ui/GoodsList/hook/useColumns/ui/TitleText/index.tsx +20 -20
  80. package/src/Invoice/ui/GoodsList/hook/useDeduction/index.tsx +24 -24
  81. package/src/Invoice/ui/GoodsList/hook/useOnRow/index.tsx +39 -39
  82. package/src/Invoice/ui/GoodsList/hook/useRowSelection/index.tsx +111 -111
  83. package/src/Invoice/ui/GoodsList/hook/useToGenerateId/index.ts +8 -8
  84. package/src/Invoice/ui/GoodsList/hook/useWindowClick/index.tsx +23 -23
  85. package/src/Invoice/ui/GoodsList/index.less +170 -170
  86. package/src/Invoice/ui/GoodsList/index.tsx +177 -177
  87. package/src/Invoice/ui/GoodsList/ui/AddRowButton/index.tsx +61 -61
  88. package/src/Invoice/ui/GoodsList/ui/BulkMenu/hooks/useAddDiscountRowButton/index.less +21 -21
  89. package/src/Invoice/ui/GoodsList/ui/BulkMenu/hooks/useAddDiscountRowButton/index.tsx +244 -244
  90. package/src/Invoice/ui/GoodsList/ui/BulkMenu/hooks/useCommodityComparisonButton/index.tsx +75 -75
  91. package/src/Invoice/ui/GoodsList/ui/BulkMenu/hooks/useDelRowButton/index.tsx +66 -66
  92. package/src/Invoice/ui/GoodsList/ui/BulkMenu/hooks/useEndowCodeButton/index.tsx +58 -58
  93. package/src/Invoice/ui/GoodsList/ui/BulkMenu/index.tsx +37 -37
  94. package/src/Invoice/ui/GoodsList/ui/DescribeSwitch/index.tsx +36 -36
  95. package/src/Invoice/ui/GoodsList/ui/Search/index.less +10 -10
  96. package/src/Invoice/ui/GoodsList/ui/Search/index.tsx +50 -50
  97. package/src/Invoice/ui/GoodsList/ui/Statistics/index.less +18 -18
  98. package/src/Invoice/ui/GoodsList/ui/Statistics/index.tsx +109 -109
  99. package/src/Invoice/ui/GoodsList/ui/TableRow/index.tsx +27 -27
  100. package/src/Invoice/ui/GoodsList/ui/TableVirtual/index.less +38 -38
  101. package/src/Invoice/ui/GoodsList/ui/TableVirtual/index.tsx +105 -105
  102. package/src/Invoice/ui/GoodsList/ui/TableVirtual.o/index.less +44 -44
  103. package/src/Invoice/ui/GoodsList/ui/TableVirtual.o/index.tsx +96 -96
  104. package/src/Invoice/ui/GoodsList/ui/TaxIncludedSwitch/index.tsx +30 -30
  105. package/src/Invoice/ui/ImportBuyerDrawer/index.tsx +75 -75
  106. package/src/Invoice/ui/ImportGoodsDrawer/index.tsx +174 -174
  107. package/src/Invoice/ui/InvoiceHeader/index.less +68 -68
  108. package/src/Invoice/ui/InvoiceHeader/index.tsx +246 -246
  109. package/src/Invoice/ui/Seller/index.less +113 -113
  110. package/src/Invoice/ui/Seller/index.tsx +98 -98
  111. package/src/Invoice/ui/Sign/index.less +14 -14
  112. package/src/Invoice/ui/Sign/index.tsx +71 -71
  113. package/src/index.ts +6 -6
  114. package/tsconfig.json +31 -31
  115. package/typings.d.ts +3 -3
  116. package/yarn.e.lock +14331 -14331
  117. package/yarn.o.lock +14800 -14800
@@ -1,441 +1,441 @@
1
- import React from 'react';
2
- import Invoice from '../../';
3
- import { Button, Drawer, Select, Modal, Input as InputAntd, Form, Tree, message } from 'kts-components-antd-x3';
4
- import { chain, bignumber } from 'mathjs';
5
- import { Input, NumberPicker } from '@formily/antd-components';
6
- import { format15 } from '../GoodsList/hook/useColumns/autoFillFn';
7
- import { LineAttributeType } from '../../InvoiceController';
8
- import IGood from '../../InvoiceController/InvoiceControllerState/GoodsListState/IGood';
9
- import { countTaxAmount } from '../../tools/calculate';
10
- import { bytesLnegth, cutStr } from '../../tools/strringFn';
11
- import { setShorthand } from '../../tools/itemName';
12
- import {
13
- SchemaForm,
14
- FormButtonGroup,
15
- createAsyncFormActions,
16
- SchemaMarkupField as Field,
17
- FormEffectHooks,
18
- } from '@formily/antd';
19
- import './index.less';
20
-
21
- const { TreeNode } = Tree;
22
- const { confirm } = Modal;
23
-
24
- export default () => {
25
- const controller = Invoice.useInvoiceController();
26
-
27
- const visible = controller.useMemo(s => s.goodsListState.endowCode.endowcodeGoodIndex.length > 0, []);
28
-
29
- const [defaultValue, setDefaultValue] = React.useState<IGood>();
30
-
31
- const onClose = React.useCallback(() => {
32
- controller.pipeline(async (s) => {
33
- s.goodsListState.endowCode.endowcodeGoodIndex = [];
34
- })();
35
- }, [controller]);
36
-
37
- // 计算赋码默认值
38
- React.useEffect(() => {
39
- if (visible) {
40
- controller.pipeline(async s => {
41
- const endowcodeGoodIndex = s.goodsListState.endowCode.endowcodeGoodIndex.filter(i => {
42
- const good = s.goodsListState.goodsMap.get(i);
43
- if (!good) return false;
44
-
45
- return good.lineAttribute !== LineAttributeType.折扣行;
46
- })
47
-
48
- const good = s.goodsListState.goodsMap.get(s.goodsListState.endowCode.endowcodeGoodIndex[0]);
49
- if (!good) return;
50
-
51
- const getDefaultValue = s.goodsListState.endowCode.getDefaultValue;
52
- if (getDefaultValue) {
53
- setDefaultValue(await getDefaultValue({ ...good }, endowcodeGoodIndex.length));
54
- } else {
55
- if (endowcodeGoodIndex.length === 1) {
56
- setDefaultValue(good);
57
- } else {
58
- setDefaultValue({ taxRate: good.taxRate } as any);
59
- }
60
- }
61
- })()
62
- } else {
63
- setDefaultValue(undefined);
64
- }
65
- }, [visible])
66
-
67
- return (
68
- <Drawer
69
- title="赋码"
70
- placement="right"
71
- destroyOnClose={true}
72
- closable={false}
73
- width={383}
74
- onClose={onClose}
75
- visible={visible}
76
- >
77
- {defaultValue && <DrawerBody defaultValue={defaultValue} />}
78
- </Drawer>
79
- );
80
- };
81
-
82
- const DrawerBody = (props: { defaultValue: IGood }) => {
83
-
84
- const controller = Invoice.useInvoiceController();
85
-
86
- const { defaultValue } = props;
87
-
88
- const actions = React.useMemo(() => createAsyncFormActions(), []);
89
-
90
- /** 税率 是否禁用 */
91
- const readOnlyTaxRate = controller.useMemo(s => {
92
- if (s.goodsListState.endowCode.getReadOnlyTaxRate) {
93
- return s.goodsListState.endowCode.getReadOnlyTaxRate(s.goodsListState);
94
- } else {
95
- return false;
96
- }
97
- }, [])
98
-
99
- /** 优惠政策 是否禁用 */
100
- const readOnlyFavouredPolicy = controller.useMemo(s => {
101
- if (s.goodsListState.endowCode.getReadOnlyFavouredPolicy) {
102
- return s.goodsListState.endowCode.getReadOnlyFavouredPolicy(s.goodsListState);
103
- } else {
104
- return false;
105
- }
106
- }, [])
107
-
108
- /** 税率列表 */
109
- const taxRateList = controller.useMemo(s => s.goodsListState.taxRateList.map((e) => ({ label: `${e}%`, value: e })), []);
110
-
111
- /** 免税类型 列表 */
112
- const taxFreeTypeList = controller.useMemo(s => s.goodsListState.endowCode.taxFreeTypeList, []);
113
-
114
- /** 优惠政策类型列表 */
115
- const favouredPolicyNameList = controller.useMemo(s => s.goodsListState.endowCode.favouredPolicyNameList, []);
116
-
117
- /** 优惠政策类型列表 */
118
- // const getTaxCategoryCodeTree = controller.useMemo(s => s.goodsListState.endowCode.getTaxCategoryCodeTree, []);
119
-
120
- /** 税率 */
121
- const [taxRate, setTaxRate] = React.useState<number>(0);
122
-
123
- /** 税收分类编码 选择组件 */
124
- const ShowSearch = React.useCallback(props => {
125
-
126
- const [dataSource, setDataSource] = React.useState<any[]>([]);
127
-
128
- const onSearch = React.useCallback(async e => {
129
- const arr = await controller.state.goodsListState.endowCode.getTaxCategoryCodeList(e);
130
- setDataSource(arr);
131
- }, [])
132
-
133
- const onChange = React.useCallback((value: string) => {
134
- if (props.onChange) {
135
- props.onChange(value);
136
- }
137
-
138
- const info = dataSource.filter(i => i.value === value)[0];
139
- if (!info) return;
140
-
141
- !readOnlyTaxRate && actions.setFieldState('taxRate', async s => {
142
- if (info.taxRate || info.taxRate === 0) {
143
- s.value = info.taxRate
144
- }
145
- });
146
-
147
- actions.setFieldState('shorthand', async (s) => {
148
- if (info.shorthand) {
149
- s.value = info.shorthand
150
- }
151
- });
152
- }, [actions, dataSource, readOnlyTaxRate])
153
-
154
- return (
155
- <Select
156
- {...props}
157
- showSearch
158
- showArrow={false}
159
- notFoundContent={null}
160
- filterOption={false}
161
- onSearch={onSearch}
162
- onChange={onChange}
163
- >
164
- {dataSource.map(e => <Select.Option key={e.value} value={e.value}>{e.label}</Select.Option>)}
165
- </Select>
166
- )
167
- }, [controller, actions])
168
-
169
- /** 税收分类编码 选择组件2 */
170
- const ShowSearch2 = React.useCallback(props => {
171
-
172
- // 是否显示
173
- const [visible, setVisible] = React.useState(false);
174
-
175
- // 税收分类编码树
176
- const [list, setList] = React.useState<any[]>();
177
-
178
- // 搜索条件
179
- const [filter, setFilter] = React.useState<{
180
- /** 税收分类编码 */
181
- taxCategoryCode?: string,
182
-
183
- /** 货物和劳务名称/简称 */
184
- val?: string
185
- }>();
186
-
187
- /** 创建 树节点 */
188
- const createTreeNode = React.useCallback(() => {
189
- if (!list) return <></>;
190
-
191
- return ctn(list);
192
-
193
- function title(label: string) {
194
- if (!filter) return label;
195
- label = (filter.taxCategoryCode ? label.split(new RegExp(filter.taxCategoryCode, 'g')) : [label]).join(`<span style="color: #1890ff;">${filter.taxCategoryCode}</span>`);
196
- label = (filter.val ? label.split(new RegExp(filter.val, 'g')) : [label]).join(`<span style="color: #1890ff;">${filter.val}</span>`);
197
- return <span dangerouslySetInnerHTML={{ __html: label }} />
198
- }
199
-
200
- function ctn(l: any[], p = '0') {
201
- if (!l || !l.length) return [<></>];
202
- return l.filter(e => e.pid === p).map(e => {
203
- return (
204
- <TreeNode title={title(e.label)} key={e.id}>
205
- {ctn(l, e.id)}
206
- </TreeNode>
207
- )
208
- })
209
- }
210
- }, [list, filter])
211
-
212
- /** 点击了节点 */
213
- const onSelect = React.useCallback((e: string[]) => {
214
- const id = e[0];
215
-
216
- // 是否叶子节点
217
- if (list?.filter(e => e.pid === id).length !== 0) { return; }
218
-
219
- const info = list?.filter(e => e.id === id)[0];
220
-
221
- !readOnlyTaxRate && actions.setFieldState('taxRate', async s => {
222
- if (info.taxRate || info.taxRate === 0) {
223
- s.value = info.taxRate
224
- }
225
- });
226
-
227
- actions.setFieldState('taxClassificationCode', async s => {
228
- if (info.id) {
229
- s.value = info.id
230
- }
231
- });
232
-
233
- actions.setFieldState('shorthand', async (s) => {
234
- if (info.shorthand) {
235
- s.value = info.shorthand
236
- }
237
- });
238
-
239
- setVisible(false);
240
- }, [list, actions, readOnlyTaxRate])
241
-
242
- React.useEffect(() => {
243
- (async () => {
244
- const fn = controller.state.goodsListState.endowCode.getTaxCategoryCodeTree || (async () => []);
245
- const list = await fn(filter?.taxCategoryCode, filter?.val);
246
- setList(list || []);
247
- })()
248
- }, [filter])
249
-
250
- React.useEffect(() => {
251
- if (visible) {
252
- setList([])
253
- }
254
- }, [visible])
255
-
256
- return (
257
- <>
258
- <InputAntd readOnly value={props.value} addonAfter={<Button size="small" type="link" onClick={() => { setVisible(true) }} >点击选择</Button>} />
259
- <Drawer
260
- title="税收分类编码"
261
- visible={visible}
262
- width={500}
263
- onClose={() => { setVisible(false) }}
264
- >
265
- <Form key={`${visible}`} >
266
- <Form.Item label="产品或服务简称" >
267
- <InputAntd onChange={e => { setFilter({ ...filter, val: e.target.value }) }} />
268
- </Form.Item>
269
- <Form.Item label="税收分类编码">
270
- <InputAntd onChange={e => { setFilter({ ...filter, taxCategoryCode: e.target.value }) }} />
271
- </Form.Item>
272
- </Form>
273
- {
274
- (list && list.length > 0)
275
- ? <Tree
276
- defaultExpandAll
277
- selectedKeys={[]}
278
- onSelect={onSelect}
279
- >
280
- {createTreeNode()}
281
- </Tree>
282
- : <span style={{ color: '#00000073' }} >请输入“产品或服务简称”或“税收分类编码”查找数据。</span>
283
- }
284
- </Drawer>
285
- </>
286
- )
287
- }, [controller, actions])
288
-
289
- // 是否享受优惠政策
290
- const [favouredPolicyMark, setFavouredPolicyMark] = React.useState<number>(0);
291
-
292
- // 确定
293
- const onSubmit = React.useCallback(values => {
294
- controller.pipeline(async s => {
295
-
296
- const endowCodeGood = s.goodsListState.endowCode.endowcodeGoodIndex.map(e => s.goodsListState.goodsMap.get(e));
297
-
298
- // 赋码
299
- endowCodeGood.forEach(good => {
300
- if (!good) return;
301
-
302
- good.itemName = setShorthand(good.itemName, values.shorthand);
303
- good.itemNameSelf = setShorthand(good.itemNameSelf, values.shorthand);
304
-
305
- good.taxClassificationCode = values.taxClassificationCode;
306
- good.taxRate = values.taxRate;
307
- good.taxFreeType = values.taxFreeType;
308
- good.favouredPolicyMark = values.favouredPolicyMark;
309
- good.favouredPolicyName = values.favouredPolicyName;
310
-
311
- const taxRate = chain(bignumber(values.taxRate)).dotDivide(bignumber(100)).add(bignumber(1)).done();
312
-
313
- // 是否含税
314
- const lineAmountExcludeTax = chain(bignumber(good.lineAmountIncludeTax)).dotDivide(taxRate).done();
315
- const priceExcludeTax = good.priceIncludeTax ? chain(bignumber(good.priceIncludeTax)).dotDivide(taxRate).done() : undefined
316
-
317
- good.lineAmountExcludeTax = lineAmountExcludeTax.toNumber().toFixed(2);
318
- good.priceExcludeTax = (priceExcludeTax ? format15(priceExcludeTax.toNumber()) : undefined) || undefined;
319
-
320
- good.taxAmount = countTaxAmount(good.lineAmountIncludeTax || 0, s.goodsListState.deduction, values.taxRate);
321
- });
322
-
323
- s.goodsListState.goodsList = s.goodsListState.goodsList.slice();
324
- s.goodsListState.endowCode.endowcodeGoodIndex = [];
325
- })();
326
- }, [controller]);
327
-
328
- const effects = React.useCallback(() => {
329
- // 税率变化
330
- FormEffectHooks.onFieldValueChange$('taxRate').subscribe((e) => {
331
- setTaxRate(e.value);
332
- actions.setFieldState('taxFreeType', async (s) => {
333
- if (e.value !== 0)
334
- s.value = undefined;
335
- });
336
- });
337
-
338
- // 是否享受优惠政策
339
- FormEffectHooks.onFieldValueChange$('favouredPolicyMark').subscribe((e) => {
340
- setFavouredPolicyMark(e.value);
341
- actions.setFieldState('favouredPolicyName', async (s) => {
342
- if (e.value === 0)
343
- s.value = undefined;
344
- });
345
- });
346
- }, [actions]);
347
-
348
- // 更新 税收分类编码列表
349
- React.useEffect(() => {
350
- if (controller.getTaxCategoryCodeList) controller.getTaxCategoryCodeList();
351
- }, [controller]);
352
-
353
- return (
354
- <SchemaForm actions={actions} components={{ ...components, showSearch: !!controller.state.goodsListState.endowCode.getTaxCategoryCodeTree ? ShowSearch2 : ShowSearch }} effects={effects}>
355
- <FormButtonGroup>
356
- <Field
357
- name="taxClassificationCode"
358
- type="showSearch"
359
- title="税收分类编码"
360
- // enum={taxCategoryCodeList}
361
- default={defaultValue?.taxClassificationCode}
362
- x-rules={[{ message: '请选择税收分类编码', required: true }]}
363
- />
364
- <Field
365
- name="shorthand"
366
- type="string"
367
- readOnly
368
- default={getShorthand(defaultValue?.itemName)}
369
- title="商品和服务分类简称"
370
- />
371
- <Field
372
- name="taxRate"
373
- type="string"
374
- title="税率"
375
- x-component-props={{ disabled: readOnlyTaxRate }}
376
- default={defaultValue?.taxRate ?? 0}
377
- enum={taxRateList}
378
- x-rules={[{ message: '请选择税率', required: true }]}
379
- />
380
- {taxRate === 0 &&
381
- <Field
382
- name="taxFreeType"
383
- type="string"
384
- title="免税类型"
385
- default={defaultValue?.taxFreeType}
386
- enum={taxFreeTypeList}
387
- x-rules={[{ message: '请选择免税类型', required: true }]}
388
- />
389
- }
390
- <Field
391
- name="favouredPolicyMark"
392
- type="number"
393
- title="是否享受优惠政策"
394
- x-component-props={{ disabled: readOnlyFavouredPolicy }}
395
- enum={[
396
- { label: '是', value: 1 },
397
- { label: '否', value: 0 },
398
- ]}
399
- default={defaultValue?.favouredPolicyMark ?? 0}
400
- x-rules={[{ message: '请选择是否享受优惠政策', required: true }]}
401
- />
402
- {favouredPolicyMark === 1 &&
403
- <Field
404
- name="favouredPolicyName"
405
- type="string"
406
- title="优惠政策类型"
407
- x-component-props={{ disabled: readOnlyFavouredPolicy }}
408
- enum={favouredPolicyNameList}
409
- default={defaultValue?.favouredPolicyName}
410
- x-rules={[{ message: '请选择是否享受优惠政策', required: true }]}
411
- />
412
- }
413
- </FormButtonGroup>
414
-
415
- <span className="kts-invoice-operate-goods-endow-code-button-list">
416
- <Button onClick={() => { actions.submit(onSubmit) }} type="primary">
417
- 确定
418
- </Button>
419
- <Button onClick={() => { controller.pipeline(async s => (s.goodsListState.endowCode.endowcodeGoodIndex = []))() }}>
420
- 取消
421
- </Button>
422
- </span>
423
- </SchemaForm>
424
- );
425
- };
426
-
427
- const components = {
428
- string: Input,
429
- number: NumberPicker,
430
- };
431
-
432
- /** 提取简称 */
433
- const getShorthand = (value?: string) => {
434
- if (!value) return ' ';
435
- const arr = value.match(/\*[^*]+\*/);
436
- if (arr) {
437
- return arr[0].split('*')[1];
438
- } else {
439
- return ' ';
440
- }
441
- };
1
+ import React from 'react';
2
+ import Invoice from '../../';
3
+ import { Button, Drawer, Select, Modal, Input as InputAntd, Form, Tree, message } from 'kts-components-antd-x3';
4
+ import { chain, bignumber } from 'mathjs';
5
+ import { Input, NumberPicker } from '@formily/antd-components';
6
+ import { format15 } from '../GoodsList/hook/useColumns/autoFillFn';
7
+ import { LineAttributeType } from '../../InvoiceController';
8
+ import IGood from '../../InvoiceController/InvoiceControllerState/GoodsListState/IGood';
9
+ import { countTaxAmount } from '../../tools/calculate';
10
+ import { bytesLnegth, cutStr } from '../../tools/strringFn';
11
+ import { setShorthand } from '../../tools/itemName';
12
+ import {
13
+ SchemaForm,
14
+ FormButtonGroup,
15
+ createAsyncFormActions,
16
+ SchemaMarkupField as Field,
17
+ FormEffectHooks,
18
+ } from '@formily/antd';
19
+ import './index.less';
20
+
21
+ const { TreeNode } = Tree;
22
+ const { confirm } = Modal;
23
+
24
+ export default () => {
25
+ const controller = Invoice.useInvoiceController();
26
+
27
+ const visible = controller.useMemo(s => s.goodsListState.endowCode.endowcodeGoodIndex.length > 0, []);
28
+
29
+ const [defaultValue, setDefaultValue] = React.useState<IGood>();
30
+
31
+ const onClose = React.useCallback(() => {
32
+ controller.pipeline(async (s) => {
33
+ s.goodsListState.endowCode.endowcodeGoodIndex = [];
34
+ })();
35
+ }, [controller]);
36
+
37
+ // 计算赋码默认值
38
+ React.useEffect(() => {
39
+ if (visible) {
40
+ controller.pipeline(async s => {
41
+ const endowcodeGoodIndex = s.goodsListState.endowCode.endowcodeGoodIndex.filter(i => {
42
+ const good = s.goodsListState.goodsMap.get(i);
43
+ if (!good) return false;
44
+
45
+ return good.lineAttribute !== LineAttributeType.折扣行;
46
+ })
47
+
48
+ const good = s.goodsListState.goodsMap.get(s.goodsListState.endowCode.endowcodeGoodIndex[0]);
49
+ if (!good) return;
50
+
51
+ const getDefaultValue = s.goodsListState.endowCode.getDefaultValue;
52
+ if (getDefaultValue) {
53
+ setDefaultValue(await getDefaultValue({ ...good }, endowcodeGoodIndex.length));
54
+ } else {
55
+ if (endowcodeGoodIndex.length === 1) {
56
+ setDefaultValue(good);
57
+ } else {
58
+ setDefaultValue({ taxRate: good.taxRate } as any);
59
+ }
60
+ }
61
+ })()
62
+ } else {
63
+ setDefaultValue(undefined);
64
+ }
65
+ }, [visible])
66
+
67
+ return (
68
+ <Drawer
69
+ title="赋码"
70
+ placement="right"
71
+ destroyOnClose={true}
72
+ closable={false}
73
+ width={383}
74
+ onClose={onClose}
75
+ visible={visible}
76
+ >
77
+ {defaultValue && <DrawerBody defaultValue={defaultValue} />}
78
+ </Drawer>
79
+ );
80
+ };
81
+
82
+ const DrawerBody = (props: { defaultValue: IGood }) => {
83
+
84
+ const controller = Invoice.useInvoiceController();
85
+
86
+ const { defaultValue } = props;
87
+
88
+ const actions = React.useMemo(() => createAsyncFormActions(), []);
89
+
90
+ /** 税率 是否禁用 */
91
+ const readOnlyTaxRate = controller.useMemo(s => {
92
+ if (s.goodsListState.endowCode.getReadOnlyTaxRate) {
93
+ return s.goodsListState.endowCode.getReadOnlyTaxRate(s.goodsListState);
94
+ } else {
95
+ return false;
96
+ }
97
+ }, [])
98
+
99
+ /** 优惠政策 是否禁用 */
100
+ const readOnlyFavouredPolicy = controller.useMemo(s => {
101
+ if (s.goodsListState.endowCode.getReadOnlyFavouredPolicy) {
102
+ return s.goodsListState.endowCode.getReadOnlyFavouredPolicy(s.goodsListState);
103
+ } else {
104
+ return false;
105
+ }
106
+ }, [])
107
+
108
+ /** 税率列表 */
109
+ const taxRateList = controller.useMemo(s => s.goodsListState.taxRateList.map((e) => ({ label: `${e}%`, value: e })), []);
110
+
111
+ /** 免税类型 列表 */
112
+ const taxFreeTypeList = controller.useMemo(s => s.goodsListState.endowCode.taxFreeTypeList, []);
113
+
114
+ /** 优惠政策类型列表 */
115
+ const favouredPolicyNameList = controller.useMemo(s => s.goodsListState.endowCode.favouredPolicyNameList, []);
116
+
117
+ /** 优惠政策类型列表 */
118
+ // const getTaxCategoryCodeTree = controller.useMemo(s => s.goodsListState.endowCode.getTaxCategoryCodeTree, []);
119
+
120
+ /** 税率 */
121
+ const [taxRate, setTaxRate] = React.useState<number>(0);
122
+
123
+ /** 税收分类编码 选择组件 */
124
+ const ShowSearch = React.useCallback(props => {
125
+
126
+ const [dataSource, setDataSource] = React.useState<any[]>([]);
127
+
128
+ const onSearch = React.useCallback(async e => {
129
+ const arr = await controller.state.goodsListState.endowCode.getTaxCategoryCodeList(e);
130
+ setDataSource(arr);
131
+ }, [])
132
+
133
+ const onChange = React.useCallback((value: string) => {
134
+ if (props.onChange) {
135
+ props.onChange(value);
136
+ }
137
+
138
+ const info = dataSource.filter(i => i.value === value)[0];
139
+ if (!info) return;
140
+
141
+ !readOnlyTaxRate && actions.setFieldState('taxRate', async s => {
142
+ if (info.taxRate || info.taxRate === 0) {
143
+ s.value = info.taxRate
144
+ }
145
+ });
146
+
147
+ actions.setFieldState('shorthand', async (s) => {
148
+ if (info.shorthand) {
149
+ s.value = info.shorthand
150
+ }
151
+ });
152
+ }, [actions, dataSource, readOnlyTaxRate])
153
+
154
+ return (
155
+ <Select
156
+ {...props}
157
+ showSearch
158
+ showArrow={false}
159
+ notFoundContent={null}
160
+ filterOption={false}
161
+ onSearch={onSearch}
162
+ onChange={onChange}
163
+ >
164
+ {dataSource.map(e => <Select.Option key={e.value} value={e.value}>{e.label}</Select.Option>)}
165
+ </Select>
166
+ )
167
+ }, [controller, actions])
168
+
169
+ /** 税收分类编码 选择组件2 */
170
+ const ShowSearch2 = React.useCallback(props => {
171
+
172
+ // 是否显示
173
+ const [visible, setVisible] = React.useState(false);
174
+
175
+ // 税收分类编码树
176
+ const [list, setList] = React.useState<any[]>();
177
+
178
+ // 搜索条件
179
+ const [filter, setFilter] = React.useState<{
180
+ /** 税收分类编码 */
181
+ taxCategoryCode?: string,
182
+
183
+ /** 货物和劳务名称/简称 */
184
+ val?: string
185
+ }>();
186
+
187
+ /** 创建 树节点 */
188
+ const createTreeNode = React.useCallback(() => {
189
+ if (!list) return <></>;
190
+
191
+ return ctn(list);
192
+
193
+ function title(label: string) {
194
+ if (!filter) return label;
195
+ label = (filter.taxCategoryCode ? label.split(new RegExp(filter.taxCategoryCode, 'g')) : [label]).join(`<span style="color: #1890ff;">${filter.taxCategoryCode}</span>`);
196
+ label = (filter.val ? label.split(new RegExp(filter.val, 'g')) : [label]).join(`<span style="color: #1890ff;">${filter.val}</span>`);
197
+ return <span dangerouslySetInnerHTML={{ __html: label }} />
198
+ }
199
+
200
+ function ctn(l: any[], p = '0') {
201
+ if (!l || !l.length) return [<></>];
202
+ return l.filter(e => e.pid === p).map(e => {
203
+ return (
204
+ <TreeNode title={title(e.label)} key={e.id}>
205
+ {ctn(l, e.id)}
206
+ </TreeNode>
207
+ )
208
+ })
209
+ }
210
+ }, [list, filter])
211
+
212
+ /** 点击了节点 */
213
+ const onSelect = React.useCallback((e: string[]) => {
214
+ const id = e[0];
215
+
216
+ // 是否叶子节点
217
+ if (list?.filter(e => e.pid === id).length !== 0) { return; }
218
+
219
+ const info = list?.filter(e => e.id === id)[0];
220
+
221
+ !readOnlyTaxRate && actions.setFieldState('taxRate', async s => {
222
+ if (info.taxRate || info.taxRate === 0) {
223
+ s.value = info.taxRate
224
+ }
225
+ });
226
+
227
+ actions.setFieldState('taxClassificationCode', async s => {
228
+ if (info.id) {
229
+ s.value = info.id
230
+ }
231
+ });
232
+
233
+ actions.setFieldState('shorthand', async (s) => {
234
+ if (info.shorthand) {
235
+ s.value = info.shorthand
236
+ }
237
+ });
238
+
239
+ setVisible(false);
240
+ }, [list, actions, readOnlyTaxRate])
241
+
242
+ React.useEffect(() => {
243
+ (async () => {
244
+ const fn = controller.state.goodsListState.endowCode.getTaxCategoryCodeTree || (async () => []);
245
+ const list = await fn(filter?.taxCategoryCode, filter?.val);
246
+ setList(list || []);
247
+ })()
248
+ }, [filter])
249
+
250
+ React.useEffect(() => {
251
+ if (visible) {
252
+ setList([])
253
+ }
254
+ }, [visible])
255
+
256
+ return (
257
+ <>
258
+ <InputAntd readOnly value={props.value} addonAfter={<Button size="small" type="link" onClick={() => { setVisible(true) }} >点击选择</Button>} />
259
+ <Drawer
260
+ title="税收分类编码"
261
+ visible={visible}
262
+ width={500}
263
+ onClose={() => { setVisible(false) }}
264
+ >
265
+ <Form key={`${visible}`} >
266
+ <Form.Item label="产品或服务简称" >
267
+ <InputAntd onChange={e => { setFilter({ ...filter, val: e.target.value }) }} />
268
+ </Form.Item>
269
+ <Form.Item label="税收分类编码">
270
+ <InputAntd onChange={e => { setFilter({ ...filter, taxCategoryCode: e.target.value }) }} />
271
+ </Form.Item>
272
+ </Form>
273
+ {
274
+ (list && list.length > 0)
275
+ ? <Tree
276
+ defaultExpandAll
277
+ selectedKeys={[]}
278
+ onSelect={onSelect}
279
+ >
280
+ {createTreeNode()}
281
+ </Tree>
282
+ : <span style={{ color: '#00000073' }} >请输入“产品或服务简称”或“税收分类编码”查找数据。</span>
283
+ }
284
+ </Drawer>
285
+ </>
286
+ )
287
+ }, [controller, actions])
288
+
289
+ // 是否享受优惠政策
290
+ const [favouredPolicyMark, setFavouredPolicyMark] = React.useState<number>(0);
291
+
292
+ // 确定
293
+ const onSubmit = React.useCallback(values => {
294
+ controller.pipeline(async s => {
295
+
296
+ const endowCodeGood = s.goodsListState.endowCode.endowcodeGoodIndex.map(e => s.goodsListState.goodsMap.get(e));
297
+
298
+ // 赋码
299
+ endowCodeGood.forEach(good => {
300
+ if (!good) return;
301
+
302
+ good.itemName = setShorthand(good.itemName, values.shorthand);
303
+ good.itemNameSelf = setShorthand(good.itemNameSelf, values.shorthand);
304
+
305
+ good.taxClassificationCode = values.taxClassificationCode;
306
+ good.taxRate = values.taxRate;
307
+ good.taxFreeType = values.taxFreeType;
308
+ good.favouredPolicyMark = values.favouredPolicyMark;
309
+ good.favouredPolicyName = values.favouredPolicyName;
310
+
311
+ const taxRate = chain(bignumber(values.taxRate)).dotDivide(bignumber(100)).add(bignumber(1)).done();
312
+
313
+ // 是否含税
314
+ const lineAmountExcludeTax = chain(bignumber(good.lineAmountIncludeTax)).dotDivide(taxRate).done();
315
+ const priceExcludeTax = good.priceIncludeTax ? chain(bignumber(good.priceIncludeTax)).dotDivide(taxRate).done() : undefined
316
+
317
+ good.lineAmountExcludeTax = lineAmountExcludeTax.toNumber().toFixed(2);
318
+ good.priceExcludeTax = (priceExcludeTax ? format15(priceExcludeTax.toNumber()) : undefined) || undefined;
319
+
320
+ good.taxAmount = countTaxAmount(good.lineAmountIncludeTax || 0, s.goodsListState.deduction, values.taxRate);
321
+ });
322
+
323
+ s.goodsListState.goodsList = s.goodsListState.goodsList.slice();
324
+ s.goodsListState.endowCode.endowcodeGoodIndex = [];
325
+ })();
326
+ }, [controller]);
327
+
328
+ const effects = React.useCallback(() => {
329
+ // 税率变化
330
+ FormEffectHooks.onFieldValueChange$('taxRate').subscribe((e) => {
331
+ setTaxRate(e.value);
332
+ actions.setFieldState('taxFreeType', async (s) => {
333
+ if (e.value !== 0)
334
+ s.value = undefined;
335
+ });
336
+ });
337
+
338
+ // 是否享受优惠政策
339
+ FormEffectHooks.onFieldValueChange$('favouredPolicyMark').subscribe((e) => {
340
+ setFavouredPolicyMark(e.value);
341
+ actions.setFieldState('favouredPolicyName', async (s) => {
342
+ if (e.value === 0)
343
+ s.value = undefined;
344
+ });
345
+ });
346
+ }, [actions]);
347
+
348
+ // 更新 税收分类编码列表
349
+ React.useEffect(() => {
350
+ if (controller.getTaxCategoryCodeList) controller.getTaxCategoryCodeList();
351
+ }, [controller]);
352
+
353
+ return (
354
+ <SchemaForm actions={actions} components={{ ...components, showSearch: !!controller.state.goodsListState.endowCode.getTaxCategoryCodeTree ? ShowSearch2 : ShowSearch }} effects={effects}>
355
+ <FormButtonGroup>
356
+ <Field
357
+ name="taxClassificationCode"
358
+ type="showSearch"
359
+ title="税收分类编码"
360
+ // enum={taxCategoryCodeList}
361
+ default={defaultValue?.taxClassificationCode}
362
+ x-rules={[{ message: '请选择税收分类编码', required: true }]}
363
+ />
364
+ <Field
365
+ name="shorthand"
366
+ type="string"
367
+ readOnly
368
+ default={getShorthand(defaultValue?.itemName)}
369
+ title="商品和服务分类简称"
370
+ />
371
+ <Field
372
+ name="taxRate"
373
+ type="string"
374
+ title="税率"
375
+ x-component-props={{ disabled: readOnlyTaxRate }}
376
+ default={defaultValue?.taxRate ?? 0}
377
+ enum={taxRateList}
378
+ x-rules={[{ message: '请选择税率', required: true }]}
379
+ />
380
+ {taxRate === 0 &&
381
+ <Field
382
+ name="taxFreeType"
383
+ type="string"
384
+ title="免税类型"
385
+ default={defaultValue?.taxFreeType}
386
+ enum={taxFreeTypeList}
387
+ x-rules={[{ message: '请选择免税类型', required: true }]}
388
+ />
389
+ }
390
+ <Field
391
+ name="favouredPolicyMark"
392
+ type="number"
393
+ title="是否享受优惠政策"
394
+ x-component-props={{ disabled: readOnlyFavouredPolicy }}
395
+ enum={[
396
+ { label: '是', value: 1 },
397
+ { label: '否', value: 0 },
398
+ ]}
399
+ default={defaultValue?.favouredPolicyMark ?? 0}
400
+ x-rules={[{ message: '请选择是否享受优惠政策', required: true }]}
401
+ />
402
+ {favouredPolicyMark === 1 &&
403
+ <Field
404
+ name="favouredPolicyName"
405
+ type="string"
406
+ title="优惠政策类型"
407
+ x-component-props={{ disabled: readOnlyFavouredPolicy }}
408
+ enum={favouredPolicyNameList}
409
+ default={defaultValue?.favouredPolicyName}
410
+ x-rules={[{ message: '请选择是否享受优惠政策', required: true }]}
411
+ />
412
+ }
413
+ </FormButtonGroup>
414
+
415
+ <span className="kts-invoice-operate-goods-endow-code-button-list">
416
+ <Button onClick={() => { actions.submit(onSubmit) }} type="primary">
417
+ 确定
418
+ </Button>
419
+ <Button onClick={() => { controller.pipeline(async s => (s.goodsListState.endowCode.endowcodeGoodIndex = []))() }}>
420
+ 取消
421
+ </Button>
422
+ </span>
423
+ </SchemaForm>
424
+ );
425
+ };
426
+
427
+ const components = {
428
+ string: Input,
429
+ number: NumberPicker,
430
+ };
431
+
432
+ /** 提取简称 */
433
+ const getShorthand = (value?: string) => {
434
+ if (!value) return ' ';
435
+ const arr = value.match(/\*[^*]+\*/);
436
+ if (arr) {
437
+ return arr[0].split('*')[1];
438
+ } else {
439
+ return ' ';
440
+ }
441
+ };