buyer_invoice.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. import React, {Component} from 'react';
  2. import {
  3. View,
  4. Text,
  5. TouchableOpacity,
  6. StyleSheet,
  7. Dimensions,
  8. FlatList,
  9. PixelRatio,
  10. DeviceEventEmitter,
  11. Image,
  12. TextInput,
  13. SafeAreaView,
  14. ScrollView,
  15. } from 'react-native';
  16. import {
  17. List,
  18. SwipeAction,
  19. Picker,
  20. Provider,
  21. WhiteSpace,
  22. WingBlank,
  23. } from '@ant-design/react-native';
  24. import public_css from '../../source/css/public_css';
  25. import {NumberTwoDecimal, RoundingData} from '../../source/inspect/inspect';
  26. import buyer_invoice_css from './buyer_invoice_css';
  27. import {SvgXml} from 'react-native-svg';
  28. import {ToastShow} from '../../components/toast/toast';
  29. import {plusIcon} from '../../source/icon/icon';
  30. import {RetrieveData} from '../../data/storage';
  31. import {RequestNetwork} from '../../data/encryption';
  32. export default class buyer_invoice extends Component {
  33. constructor(props) {
  34. super(props);
  35. this.props.navigation.dangerouslyGetParent().setOptions({
  36. tabBarVisible: false,
  37. });
  38. this.state = {
  39. listData: [],
  40. productNumberTotal: 0,
  41. taxAmount: 0.0,
  42. amountTotal: 0.0,
  43. taxRateTotal: 0.0,
  44. productAmountTotal: 0.0,
  45. companyTypes: [
  46. {
  47. label: '个人',
  48. value: '1',
  49. },
  50. {
  51. label: '企业',
  52. value: '2',
  53. },
  54. ],
  55. companyType: '1',
  56. invoiceTypes: [
  57. {
  58. label: '增值税普通电子发票',
  59. value: '1',
  60. },
  61. {
  62. label: '增值税电子专用发票',
  63. value: '2',
  64. },
  65. ],
  66. invoiceType: '1',
  67. product_name: '',
  68. customerName: '',
  69. taxNumber: '',
  70. contactNumber: '',
  71. address: '',
  72. bank: '',
  73. bankAccount: '',
  74. payee: '',
  75. reviewer: '',
  76. drawer: '',
  77. remark: '',
  78. hideStatusText: '更多',
  79. hideStatus: false,
  80. email: '',
  81. typeBack: 'rgba(42,103,254, 1)',
  82. typeBackFont: '#ffffff',
  83. typeBackMajor: 'rgba(42,103,254, 0.07)',
  84. typeBackMajorFont: '#2A67FE',
  85. };
  86. }
  87. render() {
  88. return (
  89. <Provider>
  90. <SafeAreaView style={public_css.body}>
  91. <ScrollView>
  92. <View>
  93. <View
  94. style={{
  95. backgroundColor: '#F7F7F7',
  96. height: 40,
  97. justifyContent: 'center',
  98. marginLeft: 10,
  99. }}>
  100. <Text style={{color: '#888888', fontSize: 18}}>发票类型</Text>
  101. </View>
  102. <View style={{flexDirection: 'row', justifyContent: 'center'}}>
  103. <View>
  104. <TouchableOpacity
  105. onPress={() => {
  106. this.getInvoiceType('1');
  107. }}
  108. style={{
  109. alignItems: 'center',
  110. justifyContent: 'center',
  111. backgroundColor: this.state.typeBack,
  112. width: 160,
  113. height: 40,
  114. borderRadius: 39,
  115. margin: 10,
  116. }}>
  117. <Text
  118. style={{
  119. color: this.state.typeBackFont,
  120. fontWeight: 'bold',
  121. fontSize: 16,
  122. }}>
  123. 增值税电子普通发票
  124. </Text>
  125. </TouchableOpacity>
  126. </View>
  127. <View>
  128. <TouchableOpacity
  129. onPress={() => {
  130. this.getInvoiceType('2');
  131. }}
  132. style={{
  133. alignItems: 'center',
  134. justifyContent: 'center',
  135. backgroundColor: this.state.typeBackMajor,
  136. width: 160,
  137. height: 40,
  138. borderRadius: 39,
  139. margin: 10,
  140. }}>
  141. <Text
  142. style={{
  143. color: this.state.typeBackMajorFont,
  144. fontWeight: 'bold',
  145. fontSize: 16,
  146. }}>
  147. 增值税电子专用发票
  148. </Text>
  149. </TouchableOpacity>
  150. </View>
  151. </View>
  152. <List>
  153. <View
  154. style={[
  155. public_css.view,
  156. public_css.lineTopBottom,
  157. {alignItems: 'center'},
  158. ]}>
  159. <Text style={public_css.text}>
  160. <Text style={{color: 'red'}}>*</Text>收款人:
  161. </Text>
  162. <TextInput
  163. style={public_css.textInputStyle}
  164. placeholder="请选择收款人"
  165. clearButtonMode="while-editing"
  166. secureTextEntry={false}
  167. value={this.state.payee}
  168. editable={false}
  169. />
  170. <View style={{marginRight: 20}}>
  171. <TouchableOpacity
  172. style={{width: 30, height: 30, justifyContent: 'center', alignItems: 'center'}}
  173. onPress={() => {
  174. this.props.navigation.navigate('select_user', {
  175. type: 1,
  176. getUserInfo: (type, name) => {
  177. this.getUserInfo(type, name);
  178. },
  179. });
  180. }}>
  181. <Image
  182. source={require('../../source/img/productImg/addIcon.png')}
  183. style={{height: 16, width: 16}}
  184. />
  185. </TouchableOpacity>
  186. </View>
  187. </View>
  188. <View
  189. style={[
  190. public_css.view,
  191. public_css.lineTopBottom,
  192. {alignItems: 'center'},
  193. ]}>
  194. <Text style={public_css.text}>
  195. <Text style={{color: 'red'}}>*</Text>审核人:
  196. </Text>
  197. <TextInput
  198. style={public_css.textInputStyle}
  199. placeholder="请选择审核人"
  200. clearButtonMode="while-editing"
  201. secureTextEntry={false}
  202. value={this.state.reviewer}
  203. editable={false}
  204. />
  205. <View style={{marginRight: 20}}>
  206. <TouchableOpacity
  207. style={{width: 30, height: 30, justifyContent: 'center', alignItems: 'center'}}
  208. onPress={() => {
  209. this.props.navigation.navigate('select_user', {
  210. type: 2,
  211. getUserInfo: (type, name) => {
  212. this.getUserInfo(type, name);
  213. },
  214. });
  215. }}>
  216. <Image
  217. source={require('../../source/img/productImg/addIcon.png')}
  218. style={{height: 16, width: 16}}
  219. />
  220. </TouchableOpacity>
  221. </View>
  222. </View>
  223. <View
  224. style={[
  225. public_css.view,
  226. public_css.lineTopBottom,
  227. {alignItems: 'center'},
  228. ]}>
  229. <Text style={public_css.text}>
  230. <Text style={{color: 'red'}}>*</Text>开票人:
  231. </Text>
  232. <TextInput
  233. style={public_css.textInputStyle}
  234. placeholder="请选择开票人"
  235. clearButtonMode="while-editing"
  236. secureTextEntry={false}
  237. value={this.state.drawer}
  238. editable={false}
  239. />
  240. <View style={{marginRight: 20}}>
  241. <TouchableOpacity
  242. style={{width: 30, height: 30, justifyContent: 'center', alignItems: 'center'}}
  243. onPress={() => {
  244. this.props.navigation.navigate('select_user', {
  245. type: 3,
  246. getUserInfo: (type, name) => {
  247. this.getUserInfo(type, name);
  248. },
  249. });
  250. }}>
  251. <Image
  252. source={require('../../source/img/productImg/addIcon.png')}
  253. style={{height: 16, width: 16}}
  254. />
  255. </TouchableOpacity>
  256. </View>
  257. </View>
  258. </List>
  259. <View
  260. style={{
  261. backgroundColor: '#F7F7F7',
  262. height: 40,
  263. justifyContent: 'center',
  264. marginLeft: 10,
  265. }}>
  266. <Text style={{color: '#888888', fontSize: 18}}>商品信息</Text>
  267. </View>
  268. <View style={buyer_invoice_css.list_view}>
  269. <Text style={buyer_invoice_css.list_title_text}>名称</Text>
  270. <Text style={buyer_invoice_css.list_title_text}>单价</Text>
  271. {/*<Text style={invoice_css.list_title_text}>数量</Text>*/}
  272. <Text style={buyer_invoice_css.list_title_text}>税率(%)</Text>
  273. <Text style={buyer_invoice_css.list_title_text}>税额</Text>
  274. </View>
  275. <FlatList
  276. data={this.state.listData}
  277. renderItem={(item) => this.renderItem(item)}
  278. />
  279. <View>
  280. <WhiteSpace />
  281. <WingBlank>
  282. <TouchableOpacity
  283. style={{
  284. // width: Dimensions.get('window').width,
  285. height: 52,
  286. flexDirection: 'row',
  287. justifyContent: 'center',
  288. alignItems: 'center',
  289. border: 2,
  290. borderStyle: 'dotted',
  291. borderColor: '#2A67FE',
  292. borderWidth: 2,
  293. borderRadius: 8,
  294. opacity: 1,
  295. }}
  296. onPress={() => {
  297. this.props.navigation.navigate('product_list_info', {
  298. status: 2,
  299. });
  300. }}>
  301. <SvgXml xml={plusIcon()} />
  302. <Text style={{}}>添加商品信息</Text>
  303. </TouchableOpacity>
  304. </WingBlank>
  305. <WhiteSpace />
  306. </View>
  307. </View>
  308. </ScrollView>
  309. <View>
  310. <WhiteSpace />
  311. <View
  312. style={{
  313. flexDirection: 'row',
  314. justifyContent: 'space-around',
  315. alignItems: 'center',
  316. // width: Dimensions.get('window').width,
  317. }}>
  318. <Text>共{this.state.productNumberTotal}个产品</Text>
  319. <Text>
  320. 开票金额:
  321. {RoundingData(parseFloat(this.state.amountTotal)).replace(
  322. /(\d)(?=(\d{3})+(?:\.\d+)?$)/g,
  323. '$1,',
  324. )}
  325. </Text>
  326. <Text>税额:{RoundingData(parseFloat(this.state.taxAmount))}</Text>
  327. </View>
  328. <WhiteSpace />
  329. <WingBlank>
  330. <View style={[public_css.bottomStatus]}>
  331. <TouchableOpacity
  332. style={[public_css.statusBtn, public_css.statusRBtn]}
  333. onPress={() => this.submitData()}>
  334. {/*<Image*/}
  335. {/* source={require('../../source/img/productImg/confirm.png')}*/}
  336. {/* style={{width: 32, height: 32}}*/}
  337. {/*/>*/}
  338. <Text style={{color: '#fff'}}>生成二维码</Text>
  339. </TouchableOpacity>
  340. </View>
  341. </WingBlank>
  342. <WhiteSpace />
  343. </View>
  344. </SafeAreaView>
  345. </Provider>
  346. );
  347. }
  348. // render完后后加载
  349. async componentDidMount(): void {
  350. let company = JSON.parse(await RetrieveData('company'));
  351. let userName = await RetrieveData('userName');
  352. let payee = '';
  353. let reviewer = '';
  354. if (company.payees.length > 0) {
  355. payee = company.payees.split(',')[0];
  356. }
  357. if (company.reviewers.length > 0) {
  358. reviewer = company.reviewers.split(',')[0];
  359. }
  360. this.setState({
  361. company: company,
  362. payee: payee,
  363. reviewer: reviewer,
  364. drawer: userName,
  365. });
  366. //收到监听
  367. this.listener = DeviceEventEmitter.addListener('buyerInvoice', (data) => {
  368. //收到监听后想做的事情
  369. this.setList(data);
  370. });
  371. }
  372. componentWillUnmount() {
  373. //移除监听
  374. if (this.listener) {
  375. this.listener.remove();
  376. }
  377. }
  378. // 获取收款人、审核人、开票人信息
  379. getUserInfo = (type, name) => {
  380. if (type === 1) {
  381. this.setState({
  382. payee: name,
  383. });
  384. }
  385. if (type === 2) {
  386. this.setState({
  387. reviewer: name,
  388. });
  389. }
  390. if (type === 3) {
  391. this.setState({
  392. drawer: name,
  393. });
  394. }
  395. };
  396. // 开票类型选择
  397. invoiceTypeChange = (value) => {
  398. let invoiceType = '';
  399. if (value.length > 0) {
  400. invoiceType = value[0];
  401. }
  402. this.setState({
  403. invoiceType: invoiceType,
  404. });
  405. };
  406. //提交开票信息
  407. submitData = async () => {
  408. if (this.state.payee === '') {
  409. ToastShow(1, '收款人不能为空!');
  410. return;
  411. }
  412. if (this.state.reviewer === '') {
  413. ToastShow(1, '审核人不能为空!');
  414. return;
  415. }
  416. if (this.state.drawer === '') {
  417. ToastShow(1, '开票人不能为空!');
  418. return;
  419. }
  420. if (this.state.listData <= 0) {
  421. ToastShow(1, '商品信息不能为空!');
  422. return;
  423. }
  424. const account = await RetrieveData('account');
  425. let token = await RetrieveData('token');
  426. if (token) {
  427. const url = '/sys/fapiao/todo/initSave';
  428. let response = await RequestNetwork(
  429. url,
  430. token,
  431. {
  432. cmdParam: {
  433. REQUEST_COMMON_FPKJ: {
  434. SBLX: this.state.company.defaultDeviceInfo.deviceType, //设备类型
  435. SBBH: this.state.company.defaultDeviceInfo.taxDiscId, //设备编号
  436. KPLX: 0, //开票类型 0-蓝字发票;1-红字发票
  437. FPZL: this.state.invoiceType, //发票种类 1.增值税普通电子发票 2.增值税电子专用发票 3.增值税普通纸质发票 4 增值税专用纸质发票
  438. TTLX: '', //收票客户抬头类型 1:个人 2:企业
  439. KPF_NSRSBH: this.state.company.entTaxId, //开票方纳税人识别号
  440. KPF_MC: this.state.company.entName, //开票方名称
  441. KPF_DZ: this.state.company.entAddress, //开票方地址
  442. KPF_DH: this.state.company.entPhone, //开票方电话
  443. KPF_YHZH: this.state.company.bankAccountNumber, //开票方银行账号
  444. KPF_KHHMC: this.state.company.bankName, //开票方开户行名称
  445. SPF_NSRSBH: '', //收票方纳税人识别号
  446. SPF_MC: '', //收票方名称
  447. SPF_DH: '', //收票方电话
  448. SPF_DZ: '', //收票方地址
  449. SPF_YHZH: '', //收票方银行账号
  450. SPF_KHHMC: '', //收票方开户行名称
  451. KPR: this.state.drawer, //开票人
  452. SKR: this.state.payee, //收款人
  453. FHR: this.state.reviewer, //复核人
  454. YFP_DM: '', //原发票代码
  455. YFP_HM: '', //原发票号码
  456. JSHJ: NumberTwoDecimal(parseFloat(this.state.amountTotal)), //价税合计
  457. HJJE: NumberTwoDecimal(parseFloat(this.state.productAmountTotal)), //合计金额
  458. HJSE: NumberTwoDecimal(this.state.taxRateTotal), //合计税额
  459. BZ: '', //备注
  460. HYLX: 0, //发票行性质 0 正常行、1 折扣行、2 被折扣行
  461. TSPZ: '00', //特殊票种标识 “00”不是 “01”农产品销售“02”农产品收购“06”抵扣通行费“07”其它通行费“08”成品油销售说明:如果非特殊票种此节点可以没有。
  462. COMMON_FPKJ_XMXXS: {
  463. COMMON_FPKJ_XMXX: this.state.listData,
  464. }, // 产品列表
  465. },
  466. },
  467. mobile: account,
  468. reqChannel: 3,
  469. },
  470. false,
  471. 1,
  472. );
  473. if (response) {
  474. console.log(response);
  475. if (response.code === 0) {
  476. this.props.navigation.navigate('buyer_qrcode', {
  477. url: response.data.qrcodeUrl,
  478. amount: this.state.amountTotal,
  479. });
  480. } else {
  481. ToastShow(1, response.msg);
  482. }
  483. } else {
  484. ToastShow(1, response.msg);
  485. }
  486. }
  487. };
  488. //加载list列表
  489. setList = (data) => {
  490. let numberTotal = '';
  491. if (data.XMSL === '') {
  492. numberTotal = parseInt(this.state.productNumberTotal) + 1;
  493. } else {
  494. numberTotal =
  495. parseInt(this.state.productNumberTotal) + parseInt(data.XMSL);
  496. }
  497. let taxRateTotal =
  498. parseFloat(this.state.taxRateTotal) + parseFloat(data.SE);
  499. let taxAmount =
  500. parseFloat(this.state.taxAmount) + parseFloat(data.taxAmount);
  501. let amountTotal =
  502. parseFloat(this.state.amountTotal) + parseFloat(data.amount);
  503. let productAmountTotal =
  504. parseFloat(this.state.productAmountTotal) + parseFloat(data.XMJE);
  505. let list = this.state.listData.concat(data);
  506. this.setState({
  507. listData: list,
  508. amountTotal: amountTotal,
  509. taxRateTotal: taxRateTotal,
  510. taxAmount: taxAmount,
  511. productNumberTotal: numberTotal,
  512. productAmountTotal: productAmountTotal,
  513. });
  514. };
  515. //加载items
  516. renderItem = (data) => (
  517. <SwipeAction
  518. autoClose
  519. style={{backgroundColor: 'transparent'}}
  520. right={this.right(data)}>
  521. <List.Item>
  522. <View style={{flexDirection: 'row', justifyContent: 'space-around'}}>
  523. <View style={{width: 70, alignItems: 'center'}}>
  524. <Text>{data.item.XMMC} </Text>
  525. </View>
  526. <View style={{width: 70, alignItems: 'center'}}>
  527. <Text>{data.item.price}</Text>
  528. </View>
  529. {/*<View>*/}
  530. {/* <Text>{data.item.XMSL} </Text>*/}
  531. {/*</View>*/}
  532. <View style={{width: 70, alignItems: 'center'}}>
  533. <Text>{data.item.SL * 100}</Text>
  534. </View>
  535. <View style={{width: 70, alignItems: 'center'}}>
  536. <Text>{data.item.taxAmount}</Text>
  537. </View>
  538. </View>
  539. </List.Item>
  540. </SwipeAction>
  541. );
  542. //左滑删除
  543. right = (data) => [
  544. {
  545. text: '删除',
  546. onPress: () => {
  547. this.deleteData(data.item);
  548. },
  549. style: {backgroundColor: 'red', color: 'white'},
  550. },
  551. ];
  552. //删除产品信息
  553. deleteData = (data) => {
  554. let listData = this.state.listData;
  555. let numberTotal = '';
  556. if (data.XMSL === '') {
  557. numberTotal = parseInt(this.state.productNumberTotal) - 1;
  558. } else {
  559. numberTotal =
  560. parseInt(this.state.productNumberTotal) - parseInt(data.XMSL);
  561. }
  562. let taxRateTotal =
  563. parseFloat(this.state.taxRateTotal) - parseFloat(data.SE);
  564. let taxAmount =
  565. parseFloat(this.state.taxAmount) - parseFloat(data.taxAmount);
  566. let amountTotal =
  567. parseFloat(this.state.amountTotal) - parseFloat(data.amount);
  568. let productAmountTotal =
  569. parseFloat(this.state.productAmountTotal) - parseFloat(data.XMJE);
  570. const prevIndex = listData.findIndex((item) => item.key === data.SPBM);
  571. listData.splice(prevIndex, 1);
  572. this.setState({
  573. listData: listData,
  574. amountTotal: amountTotal,
  575. taxRateTotal: taxRateTotal,
  576. taxAmount: taxAmount,
  577. productNumberTotal: numberTotal,
  578. productAmountTotal: productAmountTotal,
  579. });
  580. };
  581. //获取发票类型
  582. getInvoiceType = (invoiceType) => {
  583. if (invoiceType === '1') {
  584. this.setState({
  585. typeBack: 'rgba(42,103,254, 1)',
  586. typeBackMajor: 'rgba(42,103,254, 0.07)',
  587. typeBackFont: '#ffffff',
  588. typeBackMajorFont: '#2A67FE',
  589. invoiceType: invoiceType,
  590. });
  591. } else {
  592. this.setState({
  593. typeBack: 'rgba(42,103,254, 0.07)',
  594. typeBackMajor: 'rgba(42,103,254, 1)',
  595. typeBackFont: '#2A67FE',
  596. typeBackMajorFont: '#ffffff',
  597. invoiceType: invoiceType,
  598. });
  599. }
  600. };
  601. }
  602. const styles = StyleSheet.create({
  603. buttonView: {
  604. alignItems: 'center',
  605. backgroundColor: '#ffffff',
  606. },
  607. //通用按钮样式
  608. button: {
  609. marginTop: 5,
  610. width: Dimensions.get('window').width * 0.8,
  611. height: 34,
  612. borderRadius: 10,
  613. backgroundColor: '#1874CD',
  614. justifyContent: 'center',
  615. alignItems: 'center',
  616. },
  617. //通用按钮样式
  618. buttonText: {
  619. textAlign: 'center',
  620. color: 'white',
  621. },
  622. inputView: {
  623. padding: 5,
  624. backgroundColor: '#fff',
  625. alignItems: 'center',
  626. justifyContent: 'center',
  627. display: 'flex',
  628. },
  629. view: {
  630. flexDirection: 'row',
  631. height: 34,
  632. width: Dimensions.get('window').width * 0.8,
  633. },
  634. //通用textInput样式
  635. text: {
  636. lineHeight: 34,
  637. fontSize: 14,
  638. },
  639. //通用textInput样式
  640. lineTopBottom: {
  641. borderBottomWidth: 3 / PixelRatio.get(),
  642. borderColor: 'rgb(208,208,208)',
  643. },
  644. textInputStyle: {
  645. marginRight: 10,
  646. marginLeft: 20,
  647. fontSize: 14,
  648. marginTop: 4,
  649. },
  650. });