summaryrefslogtreecommitdiff
path: root/src/services
diff options
context:
space:
mode:
authoreug-vs <eug-vs@keemail.me>2021-03-25 23:09:49 +0300
committereug-vs <eug-vs@keemail.me>2021-03-25 23:09:49 +0300
commit062f10a25d43b875d187cf582b2ecf96d075ec26 (patch)
treec6b43379325ba22a051827e6a461a8f8fed98402 /src/services
parent77ac1549e2ab5ac68a1a7464ada9be7e2a2aad92 (diff)
downloadcommercel-ui-062f10a25d43b875d187cf582b2ecf96d075ec26.tar.gz
refactor: move services to separate folder
Diffstat (limited to 'src/services')
-rw-r--r--src/services/account/index.ts17
-rw-r--r--src/services/constants.ts11
-rw-r--r--src/services/contractors/ContractorForm.tsx14
-rw-r--r--src/services/contractors/ContractorPanel.tsx34
-rw-r--r--src/services/contractors/index.ts22
-rw-r--r--src/services/index.ts20
-rw-r--r--src/services/products/ProductForm.tsx15
-rw-r--r--src/services/products/index.ts20
-rw-r--r--src/services/transfers/TransferForm.tsx44
-rw-r--r--src/services/transfers/TransfersUpload.tsx44
-rw-r--r--src/services/transfers/index.ts35
-rw-r--r--src/services/waybills/WaybillForm.tsx86
-rw-r--r--src/services/waybills/WaybillPanel.tsx42
-rw-r--r--src/services/waybills/index.ts27
14 files changed, 431 insertions, 0 deletions
diff --git a/src/services/account/index.ts b/src/services/account/index.ts
new file mode 100644
index 0000000..5b5eb10
--- /dev/null
+++ b/src/services/account/index.ts
@@ -0,0 +1,17 @@
+const service = {
+ route: 'account',
+ name: 'Рассчётный счёт',
+ tableFields: [
+ { key: 'date', label: 'Дата', transform: (date: string) => new Date(date).toLocaleDateString() },
+ { key: 'amount', label: 'Сумма' },
+ ],
+ actions: [
+ {
+ name: 'Загрузить выписку',
+ route: '/transfers/upload',
+ },
+ ],
+ rowLink: (item: any) => `/transfers?date=${item.date}`,
+};
+
+export default service;
diff --git a/src/services/constants.ts b/src/services/constants.ts
new file mode 100644
index 0000000..1461d9c
--- /dev/null
+++ b/src/services/constants.ts
@@ -0,0 +1,11 @@
+export const operationNames = {
+ in: 'Приход',
+ out: 'Расход',
+};
+
+export const waybillStatusNames = {
+ waiting: 'Ожидание',
+ executed: 'Проведена',
+ cancelled: 'Отменена',
+};
+
diff --git a/src/services/contractors/ContractorForm.tsx b/src/services/contractors/ContractorForm.tsx
new file mode 100644
index 0000000..d300efc
--- /dev/null
+++ b/src/services/contractors/ContractorForm.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import { Form } from 'formik';
+import Input from '../../components/Input';
+
+const ContractorForm: React.FC = () => {
+ return (
+ <Form id="form">
+ <Input name="name" label="Название" />
+ <Input name="vatId" label="УНП" />
+ </Form>
+ );
+};
+
+export default ContractorForm;
diff --git a/src/services/contractors/ContractorPanel.tsx b/src/services/contractors/ContractorPanel.tsx
new file mode 100644
index 0000000..ce94c48
--- /dev/null
+++ b/src/services/contractors/ContractorPanel.tsx
@@ -0,0 +1,34 @@
+import React from 'react';
+import { useHistory } from 'react-router-dom';
+import Button from '../../components/Button';
+import { patch, baseURL } from '../../requests';
+import { PanelProps } from '../../containers/Service/ServiceContext';
+
+
+const ContractorPanel: React.FC<PanelProps> = ({ item, mutate }) => {
+ const history = useHistory();
+
+ return (
+ <div className="lg:m-4 p-4 flex flex-col lg:pl-16 lg:border-l">
+ <span className="text-lg mb-10">
+ Долг контрагента: <span className="font-bold">{item.debt}</span>
+ </span>
+ <div className="grid lg:grid-cols-2">
+ <Button route={`/waybills?contractorId=${item._id}`} variant="outlined">
+ Показать накладные
+ </Button>
+ <Button route={`/waybills/add?contractorId=${item._id}`}>
+ Новая накладная
+ </Button>
+ <Button route={`/transfers?contractorId=${item._id}`} variant="outlined">
+ Показать переводы
+ </Button>
+ <Button route={`/transfers/add?contractorId=${item._id}`}>
+ Новый перевод
+ </Button>
+ </div>
+ </div>
+ );
+};
+
+export default ContractorPanel;
diff --git a/src/services/contractors/index.ts b/src/services/contractors/index.ts
new file mode 100644
index 0000000..124e338
--- /dev/null
+++ b/src/services/contractors/index.ts
@@ -0,0 +1,22 @@
+import Form from './ContractorForm';
+import Panel from './ContractorPanel';
+
+const service = {
+ route: 'contractors',
+ name: 'Контрагенты',
+ nameSingular: 'Контрагент',
+ tableFields: [
+ { key: 'vatId', label: 'УНП' },
+ { key: 'name', label: 'Название' },
+ { key: 'debt', label: 'Долг' },
+ ],
+ default: {
+ name: '',
+ vatId: '',
+ debt: 0,
+ },
+ Form,
+ Panel,
+};
+
+export default service;
diff --git a/src/services/index.ts b/src/services/index.ts
new file mode 100644
index 0000000..7f559f2
--- /dev/null
+++ b/src/services/index.ts
@@ -0,0 +1,20 @@
+import contractors from './contractors';
+import waybills from './waybills';
+import transfers from './transfers';
+import products from './products';
+import account from './account';
+import { registerServiceHooks } from '../hooks/useAPIClient';
+import { ServiceParams } from '../containers/Service/ServiceContext';
+
+const services = [
+ contractors,
+ products,
+ waybills,
+ transfers,
+ account,
+] as ServiceParams[];
+
+services.forEach((service: any) => registerServiceHooks(service.route));
+
+export default services;
+
diff --git a/src/services/products/ProductForm.tsx b/src/services/products/ProductForm.tsx
new file mode 100644
index 0000000..62f0e70
--- /dev/null
+++ b/src/services/products/ProductForm.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { Form } from 'formik';
+import Input from '../../components/Input';
+
+
+const ProductForm: React.FC = () => {
+ return (
+ <Form id="form">
+ <Input name="name" label="Название" />
+ <Input name="price" type="number" label="Цена" />
+ </Form>
+ );
+};
+
+export default ProductForm;
diff --git a/src/services/products/index.ts b/src/services/products/index.ts
new file mode 100644
index 0000000..7e1509a
--- /dev/null
+++ b/src/services/products/index.ts
@@ -0,0 +1,20 @@
+import Form from './ProductForm';
+
+const service = {
+ route: 'products',
+ name: 'Товары',
+ nameSingular: 'Товар',
+ tableFields: [
+ { key: 'name', label: 'Название' },
+ { key: 'price', label: 'Цена' },
+ { key: 'quantity', label: 'На складе' },
+ ],
+ default: {
+ name: '',
+ price: '',
+ quantity: 0,
+ },
+ Form,
+};
+
+export default service;
diff --git a/src/services/transfers/TransferForm.tsx b/src/services/transfers/TransferForm.tsx
new file mode 100644
index 0000000..3502609
--- /dev/null
+++ b/src/services/transfers/TransferForm.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import { Form, FormikProps } from 'formik';
+import moment from 'moment';
+import Input from '../../components/Input';
+import Select from '../../components/Select';
+import hooks from '../../hooks/useAPIClient';
+
+
+const mapper = (item: any) => ({ key: item._id, label: item.name });
+
+
+const TransferForm: React.FC<FormikProps<any>> = ({ setFieldValue, values }) => {
+ const { data: contractors } = hooks.contractors.useList();
+
+ if (!values.date) setFieldValue('date', moment().format('YYYY-MM-DD'));
+ if (!values.contractorId && contractors?.length) setFieldValue('contractorId', contractors[0]._id);
+
+ return (
+ <Form id="form">
+ <div className="grid grid-cols-2">
+ <Select
+ name="contractorId"
+ label="Контрагент"
+ options={contractors?.map(mapper)}
+ required
+ />
+ <Input name="date" type="date" label="Дата" required />
+ </div>
+ <div className="grid grid-cols-2">
+ <Select
+ name="operation"
+ label="Операция"
+ options={[
+ { key: 'in', label: 'Приход' },
+ { key: 'out', label: 'Расход' },
+ ]}
+ />
+ <Input name="amount" type="number" label="Сумма" required />
+ </div>
+ </Form>
+ );
+};
+
+export default TransferForm;
diff --git a/src/services/transfers/TransfersUpload.tsx b/src/services/transfers/TransfersUpload.tsx
new file mode 100644
index 0000000..1c81b08
--- /dev/null
+++ b/src/services/transfers/TransfersUpload.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import { useHistory } from 'react-router-dom';
+import { Form, Formik } from 'formik';
+import Button from '../../components/Button';
+import Input from '../../components/Input';
+import Page, { Action } from '../../containers/Page';
+import { post } from '../../requests';
+
+const TransfersUpload: React.FC = () => {
+ const history = useHistory();
+
+ const handleSubmitFile = () => {
+ const reader = new FileReader();
+ const element = document.getElementById('file') as HTMLInputElement;
+ const file = element?.files?.[0];
+ if (file) {
+ reader.readAsDataURL(file);
+ reader.onload = (e: any) => {
+ const uri = e.target.result;
+ post('/uploads', { uri }).then(history.goBack);
+ };
+ }
+ };
+
+ const actions: Action[] = [
+ { name: 'Назад', variant: 'outlined', onClick: history.goBack },
+ { name: 'Загрузить', type: 'submit', form: 'form' },
+ ];
+
+ return (
+ <Page
+ title="Загрузить выписку"
+ actions={actions}
+ >
+ <Formik onSubmit={handleSubmitFile} initialValues={{}}>
+ <Form id="form">
+ <Input name="file" type="file" accept=".pdf" label="Прикрепите файл" id="file" />
+ </Form>
+ </Formik>
+ </Page>
+ );
+};
+
+export default TransfersUpload;
diff --git a/src/services/transfers/index.ts b/src/services/transfers/index.ts
new file mode 100644
index 0000000..09f6e04
--- /dev/null
+++ b/src/services/transfers/index.ts
@@ -0,0 +1,35 @@
+import Form from './TransferForm';
+import UploadPage from './TransfersUpload';
+
+import { operationNames } from '../constants';
+
+const service = {
+ route: 'transfers',
+ name: 'Переводы',
+ nameSingular: 'Перевод',
+ tableFields: [
+ { key: 'date', label: 'Дата', transform: (date: string) => new Date(date).toLocaleDateString() },
+ { key: 'contractor.name', label: 'Контрагент' },
+ { key: 'operation', label: 'Операция', transform: (op: 'in' | 'out') => operationNames[op] },
+ { key: 'amount', label: 'Сумма' },
+ ],
+ actions: [
+ {
+ name: 'Загрузить выписку',
+ route: '/transfers/upload',
+ variant: 'outlined',
+ },
+ {
+ name: 'Добавить',
+ route: '/transfers/add',
+ },
+ ],
+ default: {
+ operation: 'in',
+ records: [],
+ },
+ routes: { upload: UploadPage },
+ Form,
+};
+
+export default service;
diff --git a/src/services/waybills/WaybillForm.tsx b/src/services/waybills/WaybillForm.tsx
new file mode 100644
index 0000000..c11ab9e
--- /dev/null
+++ b/src/services/waybills/WaybillForm.tsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import { Form, FormikProps } from 'formik';
+import _ from 'lodash';
+import moment from 'moment';
+import Input from '../../components/Input';
+import Button from '../../components/Button';
+import Select from '../../components/Select';
+import Paper from '../../components/Paper';
+import hooks from '../../hooks/useAPIClient';
+
+
+const mapper = (item: any) => ({ key: item._id, label: item.name });
+
+
+const WaybillForm: React.FC<FormikProps<any>> = ({ setFieldValue, values }) => {
+ const { data: products } = hooks.products.useList();
+ const { data: contractors } = hooks.contractors.useList();
+
+ if (!values.date) setFieldValue('date', moment().format('YYYY-MM-DD'));
+ if (!values.contractorId && contractors?.length) setFieldValue('contractorId', contractors[0]._id);
+
+ const handleAddRecord = () => setFieldValue('records', [...values.records, {
+ productId: _.map(products, '_id').reduce((acc, id) => {
+ return acc || (!_.map(values.records, 'productId').includes(id) && id);
+ }, false),
+ price: '',
+ quantity: 1,
+ }]);
+
+ const handleRemoveRecord = (index: number) => () => {
+ const records = [...values.records];
+ records.splice(index, 1);
+ setFieldValue('records', records);
+ };
+
+ return (
+ <Form id="form">
+ <Select
+ name="contractorId"
+ label="Контрагент"
+ options={contractors?.map(mapper)}
+ />
+ <div className="grid grid-cols-2">
+ <Select
+ name="operation"
+ label="Операция"
+ options={[
+ { key: 'in', label: 'Приход' },
+ { key: 'out', label: 'Расход' },
+ ]}
+ />
+ <Input name="date" type="date" label="Дата" />
+ </div>
+ {values.records.map((record: any, index: number) => (
+ <Paper variant="outlined" className="my-4 md:mx-4" key={`${index}-${record.productId}`}>
+ <Select
+ name={`records.${index}.productId`}
+ label="Товар"
+ options={products?.map(mapper)}
+ required
+ />
+ <div className="grid grid-cols-3">
+ <Input
+ name={`records.${index}.price`}
+ type="number"
+ label="Цена"
+ required
+ />
+ <Input
+ name={`records.${index}.quantity`}
+ type="number"
+ label="Количество"
+ required
+ />
+ <div className="flex justify-end items-end">
+ <Button onClick={handleRemoveRecord(index)} size="sm" variant="outlined">Удалить</Button>
+ </div>
+ </div>
+ </Paper>
+ ))}
+ <Button onClick={handleAddRecord} variant="outlined" size="sm">Добавить товар</Button>
+ </Form>
+ );
+};
+
+export default WaybillForm;
diff --git a/src/services/waybills/WaybillPanel.tsx b/src/services/waybills/WaybillPanel.tsx
new file mode 100644
index 0000000..101a871
--- /dev/null
+++ b/src/services/waybills/WaybillPanel.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { useHistory } from 'react-router-dom';
+import Button from '../../components/Button';
+import { patch, baseURL } from '../../requests';
+import { PanelProps } from '../../containers/Service/ServiceContext';
+
+
+const WaybillPanel: React.FC<PanelProps> = ({ item, mutate }) => {
+ const history = useHistory();
+
+ const handleChangeStatus = (status: any) => patch(`/waybills/${item._id}`, { status })
+ .then(() => {
+ history.push('/waybills');
+ mutate({ ...item, status });
+ });
+
+ const handlePrint = () => window.open(`${baseURL}/spreadsheets/${item._id}`, '_blank');
+
+ const handleExecute = () => handleChangeStatus('executed');
+ const handleCancel = () => handleChangeStatus('cancelled');
+
+ const executed = item.status === 'executed';
+
+ return (
+ <div className="lg:m-4 p-4 flex flex-col lg:pl-16 lg:border-l">
+ <div className="grid lg:grid-cols-2">
+ <Button route={`/contractors/${item.contractorId}`} variant="outlined">
+ Перейти к контрагенту
+ </Button>
+ <Button onClick={handlePrint} variant="outlined">
+ Печать
+ </Button>
+ <span className="text-lg text-center mt-4">Итоговая сумма: ${item.total}</span>
+ <Button onClick={executed ? handleCancel : handleExecute} size="lg">
+ {executed ? 'Откатить' : 'Провести'}
+ </Button>
+ </div>
+ </div>
+ );
+};
+
+export default WaybillPanel;
diff --git a/src/services/waybills/index.ts b/src/services/waybills/index.ts
new file mode 100644
index 0000000..f8a4be6
--- /dev/null
+++ b/src/services/waybills/index.ts
@@ -0,0 +1,27 @@
+import Form from './WaybillForm';
+import Panel from './WaybillPanel';
+import { waybillStatusNames, operationNames } from '../constants';
+
+const service = {
+ route: 'waybills',
+ name: 'Накладные',
+ nameSingular: 'Накладная',
+ tableFields: [
+ {
+ key: 'status',
+ label: 'Статус',
+ transform: (status: 'waiting' | 'executed' | 'cancelled') => waybillStatusNames[status],
+ },
+ { key: 'operation', label: 'Операция', transform: (op: 'in' | 'out') => operationNames[op] },
+ { key: 'total', label: 'Сумма' },
+ { key: 'contractor.name', label: 'Контрагент' },
+ ],
+ default: {
+ operation: 'in',
+ records: [],
+ },
+ Form,
+ Panel,
+};
+
+export default service;