Ищете генератор счетов, который прост в использовании и позволяет настраивать ваши счета? С простым и интуитивно понятным интерфейсом Refine вы сможете создавать свои собственные счета-фактуры за несколько часов. Кроме того, мы предлагаем широкий выбор шаблонов и вариантов настройки, чтобы вы могли получить именно тот вид, который вам нужен. Узнайте больше о нашем генераторе счетов-фактур здесь!
Введение
Мы почти готовы к запуску нашего усовершенствованного генератора счетов-фактур. В этой части II статьи мы еще немного его настроим, а затем подробно рассмотрим, что можно сделать с готовым продуктом!
В этой части мы создадим миссию для услуг, которые предоставляет ваша компания. Затем мы создадим страницу счета-фактуры, используя эти миссии, а также клиентов и контакты, которые мы создали в первой части. Кроме того, вы сможете не только создавать счета-фактуры, но и просматривать и загружать их в формате PDF.
Эта статья написана в продолжение нашей статьи Разработка собственного настраиваемого генератора счетов-фактур с помощью Refine. Если вы не читали часть I, мы рекомендуем вам прочитать ее перед прочтением этой статьи.
Давайте вместе посмотрим, как легко и за короткое время мы можем разработать наш проект с помощью функций Refine.
Создание новых коллекций Strapi
В первой части нашей статьи мы создали коллекции компаний, контактов и клиентов. В этом разделе мы создадим коллекции Missions
и Invoice
Strapi для страниц миссий и счетов.
Mission Collection:
- Миссия(Название миссии): Текст
- Mission_description: Текст
- День: Число
- Суточная_ставка: Число
Invoice Collection:
- Имя: Текст
- Дата: Дата
- Компания : Отношение с компанией
- Скидка : Номер
- Налог: Номер
- Custom_id: Текст
- Контакт: Отношение с контактом
- Миссии: Отношение с миссией
Мы создали поля «Миссии» и «Счета-фактуры». Наша цель здесь — определить продукты или услуги, которые вы предлагаете конкретно вашей компании, и создать на их основе счета-фактуры. Определив количество рабочих дней продукта или услуги и их стоимость на ежедневной основе, общая сумма будет автоматически отражена в вашем счете. Теперь давайте создадим нашу страницу «Уточнение миссий», используя эту коллекцию. И давайте лучше поймем, создав пример миссии с помощью refine.
Страница Refine Missions
Давайте воспользуемся хуком useTable пакета refine-antd для создания нашей страницы и определим поля в нашем компоненте Table.
src/pages/MissionList.tsx:
import {
List,
Table,
useTable,
TagField,
useModalForm,
EditButton,
} from "@pankod/refine-antd";
import { IMission } from "interfaces";
export const MissionList: React.FC = () => {
const { tableProps } = useTable<IMission>();
return (
<List>
<Table {...tableProps}>
<Table.Column dataIndex="id" title="ID" />
<Table.Column dataIndex="mission" title="Mission" />
<Table.Column
dataIndex="mission_description"
title="Mission Description"
/>
<Table.Column dataIndex="day" title="Day(s)" />
<Table.Column
dataIndex="daily_rate"
title="Daily Rate"
render={(value) => <TagField value={value} color="red" />}
/>
<Table.Column<IMission>
title="Total"
render={(_, record) => {
return (
<TagField
value={`${record.daily_rate * record.day} $`}
color="green"
/>
);
}}
/>
<Table.Column<IMission>
title="Actions"
dataIndex="actions"
key="actions"
render={(_value, record) => (
<EditButton
hideText
size="small"
recordItemId={record.id}
onClick={() => editShow(record.id)}
/>
)}
/>
</Table>
</List>
);
};
Мы определили поля, которые мы создали на стороне strapi с помощью refine Table, и создали нашу таблицу. Давайте посмотрим, как выглядит наша таблица.
Как видите, благодаря уточнению мы смогли создать и отобразить нашу таблицу очень просто. Теперь давайте узнаем, как создать миссию из нашего интерфейса refine.
Страница создания миссий Refine
Давайте создадим модальный компонент для нашей страницы Mission Create
. Подключим наши поля с помощью Modal и Form из пакета refine-antd
.
src/components/mission/CreateMission.tsx:
import {
Modal,
Form,
Input,
ModalProps,
FormProps,
InputNumber,
} from "@pankod/refine-antd";
type CreateMissionProps = {
modalProps: ModalProps;
formProps: FormProps;
};
export const CreateMission: React.FC<CreateMissionProps> = ({
modalProps,
formProps,
}) => {
return (
<Modal {...modalProps} title="Create Contact">
<Form {...formProps} layout="vertical">
<Form.Item
label="Title"
name="mission"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
<Form.Item label="Description" name="mission_description">
<Input />
</Form.Item>
<Form.Item label="Day(s)" name="day">
<InputNumber defaultValue={1} />
</Form.Item>
<Form.Item label="Daily Rate" name="daily_rate">
<InputNumber defaultValue={1} />
</Form.Item>
</Form>
</Modal>
);
};
Определим компонент CreateMission
, который мы создали выше, в нашем MissionList
и заполним его реквизит с помощью refine useModalForm.
src/pages/MissionList.tsx:
import {
List,
Table,
useTable,
TagField,
useModalForm,
} from "@pankod/refine-antd";
import { IMission } from "interfaces";
import { CreateMission, EditMission } from "components/mission";
export const MissionList: React.FC = () => {
const { tableProps } = useTable<IMission>();
const { formProps, modalProps, show } = useModalForm({
resource: "missions",
action: "create",
});
return (
<>
<List
createButtonProps={{
onClick: () => {
show();
},
}}
>
<Table {...tableProps}>
<Table.Column dataIndex="id" title="ID" />
<Table.Column dataIndex="mission" title="Mission" />
<Table.Column
dataIndex="mission_description"
title="Mission Description"
/>
<Table.Column dataIndex="day" title="Day(s)" />
<Table.Column
dataIndex="daily_rate"
title="Daily Rate"
render={(value) => (
<TagField value={value} color="red" />
)}
/>
<Table.Column<IMission>
title="Total"
render={(_, record) => {
return (
<TagField
value={`${
record.daily_rate * record.day
} $`}
color="green"
/>
);
}}
/>
</Table>
</List>
<CreateMission modalProps={modalProps} formProps={formProps} />
</>
);
};
Страница миссий теперь готова, вы можете создавать и управлять продуктами или услугами вашего бизнеса здесь с помощью refine.
Наш следующий шаг — создание счетов-фактур в соответствии с этими заданиями и клиентами. Давайте создадим, организуем и отобразим счета-фактуры с помощью Refine.
Страница счетов-фактур Refine
Давайте поместим поля Invoice Collections
, которые мы создали с помощью Strapi, в нашу таблицу, используя fetch refine-antd useTable. Наша коллекция счетов-фактур имеет связь с коллекциями клиентов, компаний и миссий.
Благодаря refine-strapi-v4 dataProvider мы можем использовать данные коллекций, которые связаны друг с другом.
Для того чтобы использовать поля коллекций, связанных друг с другом, мы должны заполнить коллекции в metaData
.
Заполните в metaData контакты, компании и миссии, связанные с нашей коллекцией Invoice.
src/pages/InvoiceList.tsx:
import {
List,
Table,
useTable,
DateField,
TagField,
EmailField,
Space,
DeleteButton,
EditButton,
Icons,
Button,
Modal,
} from "@pankod/refine-antd";
import { IInvoice } from "interfaces";
import { PdfLayout } from "components/pdf";
const { FilePdfOutlined } = Icons;
export const InvoiceList: React.FC = () => {
const { tableProps } = useTable<IInvoice>({
metaData: {
populate: {
contact: { populate: ["client"] },
company: { populate: ["logo"] },
missions: "*",
},
},
});
return (
<>
<List>
<Table {...tableProps}>
<Table.Column dataIndex="id" title="ID" />
<Table.Column<IInvoice>
dataIndex="name"
title="Invoice Name"
render={(_, record) => {
return `Invoice_#${record.id}${record.name}`;
}}
/>
<Table.Column<IInvoice>
dataIndex="date"
title="Invoice Date"
render={(value) => (
<DateField format="LL" value={value} />
)}
/>
<Table.Column
dataIndex={["company", "name"]}
title="Your Company"
/>
<Table.Column
dataIndex={"missions"}
title="Missions"
render={(value) => {
return value.map((item: any) => {
return (
<TagField
color="blue"
value={item.mission}
/>
);
});
}}
/>
<Table.Column
dataIndex="discount"
title="Discount(%)"
render={(value) => (
<TagField color="blue" value={value} />
)}
/>
<Table.Column
dataIndex="tax"
title="Tax(%)"
render={(value) => (
<TagField color="cyan" value={value} />
)}
/>
<Table.Column
dataIndex="custom_id"
title="Custom Invoice ID"
/>
<Table.Column
dataIndex={["contact", "email"]}
title="Contact"
render={(value) => <EmailField value={value} />}
/>
<Table.Column<IInvoice>
title="Actions"
dataIndex="actions"
render={(_, record) => {
return (
<Space>
<EditButton
hideText
size="small"
recordItemId={record.id}
/>
<DeleteButton
hideText
size="small"
recordItemId={record.id}
/>
</Space>
);
}}
/>
</Table>
</List>
</>
);
};
Как вы можете видеть, мы смогли вывести список счетов-фактур с помощью refine. Используя коллекцию Invoice и связанные с ней поля, мы можем создать полнофункциональный счет-фактуру.
Наш счет-фактура содержит всю необходимую информацию. С помощью Refine Invoice Generator
вы можете определить компанию, выписывающую счет, процент скидки, процент налога, customId и подобную информацию в одном счете.
Давайте лучше разберемся в этом на примере создания счета-фактуры в нашем пользовательском интерфейсе Refine.
Страница Refine Create Invoice Page
Здесь мы сначала получаем данные о компании, контактах и миссиях с помощью хука useSelect в refine и, передавая их компоненту Select, создаем выбираемые компоненты для детализации нашего счета.
Затем мы заполняем наши компоненты refine Create и Form полями коллекции в ремешке, чтобы выполнить процесс создания, как мы делали в наших предыдущих примерах.
src/pages/invoice/CreateInvoice:
import { IResourceComponentsProps } from "@pankod/refine-core";
import {
Create,
Form,
Input,
Select,
useForm,
useSelect,
DatePicker,
} from "@pankod/refine-antd";
import { ICompany, IContact, IMission, IInvoice } from "interfaces";
export const CreateInvoice: React.FC<IResourceComponentsProps> = () => {
const { formProps, saveButtonProps } = useForm<IInvoice>();
const { selectProps: companySelectProps } = useSelect<ICompany>({
resource: "companies",
optionLabel: "name",
});
const { selectProps: contactSelectProps } = useSelect<IContact>({
resource: "contacts",
optionLabel: "first_name",
});
const { selectProps: missionSelectProps } = useSelect<IMission>({
resource: "missions",
optionLabel: "mission",
});
return (
<Create saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item label="Invoice Name" name="name">
<Input />
</Form.Item>
<Form.Item
label="Select Your Company"
name="company"
rules={[
{
required: true,
},
]}
>
<Select {...companySelectProps} />
</Form.Item>
<Form.Item
label="Mission"
name="missions"
rules={[
{
required: true,
},
]}
>
<Select {...missionSelectProps} mode="multiple" />
</Form.Item>
<Form.Item label="Discount(%)" name="discount">
<Input />
</Form.Item>
<Form.Item label="Tax(%)" name="tax">
<Input />
</Form.Item>
<Form.Item label="Custom ID" name="custom_id">
<Input />
</Form.Item>
<Form.Item
label="Contact"
name="contact"
rules={[
{
required: true,
},
]}
>
<Select {...contactSelectProps} />
</Form.Item>
<Form.Item label="Invoice Date" name="date">
<DatePicker style={{ width: "50%" }} />
</Form.Item>
</Form>
</Create>
);
};
Наш генератор счетов-фактур почти готов! Как вы можете видеть, теперь мы можем создать полноценный счет-фактуру с помощью функции refine и отобразить его в нашей таблице. В качестве последнего шага давайте просмотрим и загрузим созданные нами счета-фактуры в формате PDF.
Просмотр и загрузка счета-фактуры в формате PDF
В этом примере мы будем использовать пакет KendoReact PDF для просмотра в формате PDF. Начнем наш процесс с установки нашего пакета.
Начнем наш процесс с установки нашего пакета.
Установка
npm i @progress/kendo-react-pdf
Использование
Для начала давайте создадим макет pdf и добавим реквизиты для получения данных из списка счетов-фактур.
src/components/pdf/PdfLayout.tsx:
import { useRef } from "react";
import "./pdf.css";
import { PDFExport } from "@progress/kendo-react-pdf";
import { IInvoice } from "interfaces";
type PdfProps = {
record: IInvoice | undefined;
};
export const PdfLayout: React.FC<PdfProps> = ({ record }) => {
return <></>;
};
Давайте создадим кнопку для отображения нашего расположения PDF в списке счетов-фактур, а также модальный компонент для появления этого поля.
src/pages/invoice/InvoiceList.tsx:
import { useState } from "react";
import { useModal } from "@pankod/refine-core";
import {
List,
Table,
useTable,
DateField,
TagField,
EmailField,
Space,
DeleteButton,
EditButton,
Icons,
Button,
Modal,
} from "@pankod/refine-antd";
import { IInvoice } from "interfaces";
import { PdfLayout } from "components/pdf";
const { FilePdfOutlined } = Icons;
export const InvoiceList: React.FC = () => {
const [record, setRecord] = useState<IInvoice>();
const { tableProps } = useTable<IInvoice>({
metaData: {
populate: {
contact: { populate: ["client"] },
company: { populate: ["logo"] },
missions: "*",
},
},
});
const { show, visible, close } = useModal();
return (
<>
<List>
<Table {...tableProps}>
...
<Table.Column<IInvoice>
title="Actions"
dataIndex="actions"
render={(_, record) => {
return (
<Space>
<EditButton
hideText
size="small"
recordItemId={record.id}
/>
<DeleteButton
hideText
size="small"
recordItemId={record.id}
/>
<Button
size="small"
icon={<FilePdfOutlined />}
onClick={() => {
setRecord(record);
show();
}}
/>
</Space>
);
}}
/>
</Table>
</List>
<Modal visible={visible} onCancel={close} width={700} footer={null}>
<PdfLayout record={record} />
</Modal>
</>
);
};
Мы создали кнопку в списке счетов-фактур, и когда эта кнопка нажата, мы показываем модальный компонент, который содержит созданный нами PdfLayout. Наконец, как вы можете видеть, мы передали данные записей в списке счетов в качестве реквизитов PdfLayout.
Теперь, когда у нас есть данные о счетах-фактурах, мы можем редактировать PdfLayout.
Посмотрите дизайн и код PdfLayout
Заключение
В этом посте мы создали полностью настраиваемое и полностью функциональное приложение Invoice Generator. Если вы хотите создать приложение, подобное этому, вы можете добавить любую функцию, усовершенствовать и персонализировать генератор счетов по своему вкусу. Мы разработали приложение за очень короткое время, благодаря функциям refine и возможностям, которые он предоставляет для настройки.
С помощью refine вы можете разработать любое веб-приложение или панель администратора за очень короткое время.
Благодаря функциям refine headless и SSR-Next.js, можно легко и просто разрабатывать как B2B, так и B2C приложения, используя один фреймворк.
Живой пример CodeSandbox
Загрузка PDF может не работать в режиме CodeSandbox. С помощью этой ссылки вы можете открыть пример в браузере и попробовать его.
-
Имя пользователя
: demo -
Пароль
: demodemo
Ссылка на CodeSandbox
Исходный код
Для получения дополнительной информации о функции refine ->