@floristcloud/api-lib 1.2.115 → 1.2.117
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.
- package/build/commands/index.js +1 -0
- package/build/commands/report/get-write-off-summary.query.js +82 -0
- package/build/commands/report/index.js +1 -0
- package/build/commands/transfer-document/create-transfer-document.command.js +31 -0
- package/build/commands/transfer-document/delete-transfer-document.command.js +26 -0
- package/build/commands/transfer-document/get-transfer-document-list.query.js +23 -0
- package/build/commands/transfer-document/get-transfer-document.query.js +15 -0
- package/build/commands/transfer-document/index.js +21 -0
- package/build/commands/transfer-document/issue-transfer-document.command.js +17 -0
- package/build/constant/error-i18n-key.js +1 -0
- package/build/constant/error.js +54 -0
- package/build/constant/index.js +2 -0
- package/build/constant/okei.js +16 -0
- package/build/constant/oksm.js +72 -0
- package/build/constant/report.constant.js +8 -1
- package/build/enum/index.js +5 -0
- package/build/enum/invoice-product-field.enum.js +18 -0
- package/build/enum/transfer-document-item-kind.enum.js +15 -0
- package/build/enum/transfer-document-kind.enum.js +9 -0
- package/build/enum/transfer-document-state.enum.js +8 -0
- package/build/enum/write-off-report-date-basis.enum.js +18 -0
- package/build/schemas/index.js +2 -0
- package/build/schemas/settings/settings.schema.js +37 -0
- package/build/schemas/transfer-document/transfer-document-detailed.schema.js +37 -0
- package/build/schemas/transfer-document/transfer-document.schema.js +42 -0
- package/commands/index.ts +1 -0
- package/commands/report/get-write-off-summary.query.ts +90 -0
- package/commands/report/index.ts +1 -0
- package/commands/transfer-document/create-transfer-document.command.ts +34 -0
- package/commands/transfer-document/delete-transfer-document.command.ts +28 -0
- package/commands/transfer-document/get-transfer-document-list.query.ts +25 -0
- package/commands/transfer-document/get-transfer-document.query.ts +17 -0
- package/commands/transfer-document/index.ts +5 -0
- package/commands/transfer-document/issue-transfer-document.command.ts +19 -0
- package/constant/error-i18n-key.ts +1 -0
- package/constant/error.ts +54 -0
- package/constant/index.ts +2 -0
- package/constant/okei.ts +14 -0
- package/constant/oksm.ts +69 -0
- package/constant/report.constant.ts +9 -0
- package/enum/index.ts +5 -0
- package/enum/invoice-product-field.enum.ts +14 -0
- package/enum/transfer-document-item-kind.enum.ts +11 -0
- package/enum/transfer-document-kind.enum.ts +5 -0
- package/enum/transfer-document-state.enum.ts +4 -0
- package/enum/write-off-report-date-basis.enum.ts +14 -0
- package/package.json +1 -1
- package/schemas/index.ts +2 -0
- package/schemas/settings/settings.schema.ts +38 -0
- package/schemas/transfer-document/transfer-document-detailed.schema.ts +36 -0
- package/schemas/transfer-document/transfer-document.schema.ts +41 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TransferDocumentDetailedSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const transfer_document_item_kind_enum_1 = require("../../enum/transfer-document-item-kind.enum");
|
|
6
|
+
const money_schema_1 = require("../money.schema");
|
|
7
|
+
const transfer_document_schema_1 = require("./transfer-document.schema");
|
|
8
|
+
// Строка табличной части — снимок графы в графу на момент выпуска. Значения уже готовы к печати:
|
|
9
|
+
// пересчитывать их из заказа нельзя, выданная первичка обязана воспроизводиться неизменной.
|
|
10
|
+
const TransferDocumentItemSchema = zod_1.z.object({
|
|
11
|
+
kind: zod_1.z.nativeEnum(transfer_document_item_kind_enum_1.TransferDocumentItemKindEnum),
|
|
12
|
+
orderUUID: zod_1.z.string(),
|
|
13
|
+
orderId: zod_1.z.number(),
|
|
14
|
+
// Графа А — код товара; графы 2 / 2а — код и обозначение ОКЕИ.
|
|
15
|
+
code: zod_1.z.string().nullable(),
|
|
16
|
+
name: zod_1.z.string(),
|
|
17
|
+
unitCode: zod_1.z.string().nullable(),
|
|
18
|
+
unitName: zod_1.z.string().nullable(),
|
|
19
|
+
quantity: zod_1.z.number(),
|
|
20
|
+
priceWithoutVat: money_schema_1.MoneySchema,
|
|
21
|
+
amountWithoutVat: money_schema_1.MoneySchema,
|
|
22
|
+
// null — «Без НДС»: прочерк в графе 8. Ноль значил бы «ставка есть, налог нулевой».
|
|
23
|
+
vatRate: zod_1.z.number().nullable(),
|
|
24
|
+
vatAmount: money_schema_1.MoneySchema.nullable(),
|
|
25
|
+
amountWithVat: money_schema_1.MoneySchema,
|
|
26
|
+
// Графы 10 / 10а / 11. Пусто у услуг и доставки, а также когда страну не удалось определить.
|
|
27
|
+
countryCode: zod_1.z.string().nullable(),
|
|
28
|
+
countryName: zod_1.z.string().nullable(),
|
|
29
|
+
customsDeclarationNumber: zod_1.z.string().nullable(),
|
|
30
|
+
});
|
|
31
|
+
/** Документ вместе с табличной частью — карточка и ответ на создание. */
|
|
32
|
+
exports.TransferDocumentDetailedSchema = transfer_document_schema_1.TransferDocumentSchema.extend({
|
|
33
|
+
items: TransferDocumentItemSchema.array(),
|
|
34
|
+
// Позиции, у которых не определилась страна происхождения: документ выпущен, графы 10/10а
|
|
35
|
+
// напечатаны прочерком, а UI показывает, какие карточки товара стоит поправить.
|
|
36
|
+
warnings: zod_1.z.string().array(),
|
|
37
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TransferDocumentSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
const transfer_document_state_enum_1 = require("../../enum/transfer-document-state.enum");
|
|
6
|
+
const money_schema_1 = require("../money.schema");
|
|
7
|
+
// Заказы, вошедшие в документ. Список короткий — документ выпускается по одной отгрузке клиенту,
|
|
8
|
+
// поэтому он есть и в строке списка: по нему UI показывает, какие заказы уже закрыты первичкой.
|
|
9
|
+
const TransferDocumentOrderSchema = zod_1.z.object({
|
|
10
|
+
orderUUID: zod_1.z.string(),
|
|
11
|
+
orderId: zod_1.z.number(),
|
|
12
|
+
completedAt: zod_1.z.coerce.date().nullable(),
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* Документ без табличной части — форма списка.
|
|
16
|
+
*
|
|
17
|
+
* Позиции сюда не входят намеренно: в УПД их столько же, сколько строк в заказах,
|
|
18
|
+
* и страница списка из двадцати документов везла бы тысячи строк. За позициями —
|
|
19
|
+
* `TransferDocumentDetailedSchema` на карточке.
|
|
20
|
+
*/
|
|
21
|
+
exports.TransferDocumentSchema = zod_1.z.object({
|
|
22
|
+
uuid: zod_1.z.string(),
|
|
23
|
+
// Номер с ведущими нулями — `01887`, ровно как он напечатан в документе.
|
|
24
|
+
number: zod_1.z.string(),
|
|
25
|
+
documentDate: zod_1.z.coerce.date(),
|
|
26
|
+
shipmentDate: zod_1.z.coerce.date(),
|
|
27
|
+
// 1 — счёт-фактура + передаточный документ, 2 — только передаточный документ (акт).
|
|
28
|
+
// В MVP выпускается только 2.
|
|
29
|
+
documentStatus: zod_1.z.number(),
|
|
30
|
+
state: zod_1.z.nativeEnum(transfer_document_state_enum_1.TransferDocumentStateEnum),
|
|
31
|
+
amount: money_schema_1.MoneySchema,
|
|
32
|
+
amountWithoutVat: money_schema_1.MoneySchema,
|
|
33
|
+
vatAmount: money_schema_1.MoneySchema,
|
|
34
|
+
clientUUID: zod_1.z.string(),
|
|
35
|
+
// Имя покупателя, напечатанное в документе (строка 6 формы). Может отличаться от текущего
|
|
36
|
+
// имени в карточке клиента: у юрлица печатается `fullCompanyName`, а карточку с тех пор
|
|
37
|
+
// могли переименовать. Список называет контрагента так же, как переданная ему бумага.
|
|
38
|
+
buyerName: zod_1.z.string(),
|
|
39
|
+
orders: TransferDocumentOrderSchema.array(),
|
|
40
|
+
fileUrl: zod_1.z.string().nullable(),
|
|
41
|
+
createdAt: zod_1.z.coerce.date(),
|
|
42
|
+
});
|
package/commands/index.ts
CHANGED
|
@@ -60,3 +60,4 @@ export { ValidateSessionS2SContractQuery } from './session/validate-session-s2s.
|
|
|
60
60
|
export { CreateWsTicketContractCommand } from './session/create-ws-ticket.command';
|
|
61
61
|
export { ValidateWsTicketS2SContractQuery } from './session/validate-ws-ticket-s2s.query';
|
|
62
62
|
export * from './consignment-transfer';
|
|
63
|
+
export * from './transfer-document';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { dateRangeCheck, isStatementPeriodWithinLimit } from '../../helpers/date.helper';
|
|
3
|
+
import { MoneySchema } from '../../schemas/money.schema';
|
|
4
|
+
import { WriteOffReportDateBasisEnum } from '../../enum/write-off-report-date-basis.enum';
|
|
5
|
+
import {
|
|
6
|
+
REPORT_EXCLUDE_CLIENT_LIMIT,
|
|
7
|
+
REPORT_WRITE_OFF_CLIENT_LIMIT_DEFAULT,
|
|
8
|
+
REPORT_WRITE_OFF_CLIENT_LIMIT_MAX,
|
|
9
|
+
} from '../../constant/report.constant';
|
|
10
|
+
|
|
11
|
+
const GetWriteOffSummaryRequestSchema = z
|
|
12
|
+
.object({
|
|
13
|
+
startDate: z.coerce.date(),
|
|
14
|
+
endDate: z.coerce.date(),
|
|
15
|
+
dateBasis: z.nativeEnum(WriteOffReportDateBasisEnum).default(WriteOffReportDateBasisEnum.WRITE_OFF_DATE),
|
|
16
|
+
// Тот же формат, что в ReportOrderFilterSchema: CSV или повтор параметра. Применяется
|
|
17
|
+
// только к разрезу по клиентам — у складских списаний клиента нет.
|
|
18
|
+
excludeClientUUID: z
|
|
19
|
+
.union([z.string(), z.array(z.string())])
|
|
20
|
+
.transform(value => (Array.isArray(value) ? value : value.split(',')).map(item => item.trim()).filter(Boolean))
|
|
21
|
+
.pipe(z.array(z.string().uuid()).max(REPORT_EXCLUDE_CLIENT_LIMIT))
|
|
22
|
+
.optional(),
|
|
23
|
+
clientLimit: z.coerce
|
|
24
|
+
.number()
|
|
25
|
+
.int()
|
|
26
|
+
.positive()
|
|
27
|
+
.max(REPORT_WRITE_OFF_CLIENT_LIMIT_MAX)
|
|
28
|
+
.default(REPORT_WRITE_OFF_CLIENT_LIMIT_DEFAULT),
|
|
29
|
+
})
|
|
30
|
+
.refine(value => dateRangeCheck(value.startDate, value.endDate), {
|
|
31
|
+
message: 'validation.dateRange',
|
|
32
|
+
path: ['endDate', 'startDate'],
|
|
33
|
+
})
|
|
34
|
+
.refine(value => isStatementPeriodWithinLimit(value.startDate, value.endDate), {
|
|
35
|
+
message: 'validation.reportPeriodMax',
|
|
36
|
+
path: ['endDate', 'startDate'],
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const WriteOffSummaryReasonRowSchema = z.object({
|
|
40
|
+
// Свободный текст из справочника причин, схлопнут только по краевым пробелам (TRIM).
|
|
41
|
+
// Регистр не нормализуем: «Брак» и «брак» останутся разными строками.
|
|
42
|
+
reason: z.string(),
|
|
43
|
+
units: z.number(),
|
|
44
|
+
cost: MoneySchema,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const WriteOffSummaryClientRowSchema = z.object({
|
|
48
|
+
clientUUID: z.string(),
|
|
49
|
+
clientName: z.string(),
|
|
50
|
+
orderCount: z.number(),
|
|
51
|
+
units: z.number(),
|
|
52
|
+
cost: MoneySchema,
|
|
53
|
+
orderAmount: MoneySchema,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const GetWriteOffSummaryResponseSchema = z.object({
|
|
57
|
+
message: z.string().optional(),
|
|
58
|
+
data: z.object({
|
|
59
|
+
// totals = warehouse + byClient, считается по всем строкам — усечение `clientLimit`
|
|
60
|
+
// на итоги не влияет.
|
|
61
|
+
totals: z.object({
|
|
62
|
+
units: z.number(),
|
|
63
|
+
cost: MoneySchema,
|
|
64
|
+
}),
|
|
65
|
+
// Списания без заказа: до этого отчёта они не попадали ни в одну сводку.
|
|
66
|
+
warehouse: z.object({
|
|
67
|
+
units: z.number(),
|
|
68
|
+
cost: MoneySchema,
|
|
69
|
+
byReason: WriteOffSummaryReasonRowSchema.array(),
|
|
70
|
+
}),
|
|
71
|
+
// Списания по заказу: клиенту они уже вернулись на баланс, то есть это выручка,
|
|
72
|
+
// которой по факту не было.
|
|
73
|
+
byClient: z.object({
|
|
74
|
+
units: z.number(),
|
|
75
|
+
cost: MoneySchema,
|
|
76
|
+
orderAmount: MoneySchema,
|
|
77
|
+
rows: WriteOffSummaryClientRowSchema.array(),
|
|
78
|
+
// Сколько клиентов всего — чтобы отличить усечённый ответ от полного.
|
|
79
|
+
rowsTotal: z.number(),
|
|
80
|
+
}),
|
|
81
|
+
}),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export namespace GetWriteOffSummaryContractQuery {
|
|
85
|
+
export const RequestSchema = GetWriteOffSummaryRequestSchema;
|
|
86
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
87
|
+
|
|
88
|
+
export const ResponseSchema = GetWriteOffSummaryResponseSchema;
|
|
89
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
90
|
+
}
|
package/commands/report/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './export-client-statement.query';
|
|
|
12
12
|
export * from './get-report-by-client-weeks.query';
|
|
13
13
|
export * from './get-daily-orders-summary.query';
|
|
14
14
|
export * from './get-cash-flow.query';
|
|
15
|
+
export * from './get-write-off-summary.query';
|
|
15
16
|
export * from './get-inventory-stock.query';
|
|
16
17
|
export * from './get-inventory-turnover.query';
|
|
17
18
|
export * from './get-sales-by-client.query';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TransferDocumentDetailedSchema } from '../../schemas/transfer-document/transfer-document-detailed.schema';
|
|
3
|
+
|
|
4
|
+
// Потолок числа заказов в одном документе — защита от абсурдного запроса, а не бизнес-правило.
|
|
5
|
+
// Тот же порядок, что у счёта: сто заказов в одной отгрузке клиенту не встречаются, а документ
|
|
6
|
+
// такого размера ещё собирается и читается.
|
|
7
|
+
const MAX_TRANSFER_DOCUMENT_ORDER_COUNT = 100;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Документ выпускается по отгруженным заказам одного клиента.
|
|
11
|
+
*
|
|
12
|
+
* `documentDate` — дата составления (строка 1 формы). `shipmentDate` — дата передачи (строка [11]);
|
|
13
|
+
* не передана — берём максимальную `completedAt` из заказов, а легаси-заказу без даты её же
|
|
14
|
+
* записываем обратно, иначе заказ и документ разъедутся.
|
|
15
|
+
*/
|
|
16
|
+
const CreateTransferDocumentRequestSchema = z.object({
|
|
17
|
+
clientUUID: z.uuid(),
|
|
18
|
+
orderUUIDs: z.uuid().array().min(1).max(MAX_TRANSFER_DOCUMENT_ORDER_COUNT),
|
|
19
|
+
documentDate: z.coerce.date(),
|
|
20
|
+
shipmentDate: z.coerce.date().optional(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const CreateTransferDocumentResponseSchema = z.object({
|
|
24
|
+
message: z.string().optional(),
|
|
25
|
+
data: TransferDocumentDetailedSchema,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export namespace CreateTransferDocumentContractCommand {
|
|
29
|
+
export const RequestSchema = CreateTransferDocumentRequestSchema;
|
|
30
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
31
|
+
|
|
32
|
+
export const ResponseSchema = CreateTransferDocumentResponseSchema;
|
|
33
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { queryBooleanSchema } from '../../helpers/query-boolean.helper';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Удаление документа. Заказы отвязываются и снова становятся редактируемыми, номер сгорает —
|
|
6
|
+
* повтор получит следующий, а не дубль к тому, что уже лежит у контрагента.
|
|
7
|
+
*
|
|
8
|
+
* `force` приходит в query-строке и нужен только для выданного (`ISSUED`) документа: без него
|
|
9
|
+
* такое удаление отклоняется, чтобы фронт успел показать предупреждение.
|
|
10
|
+
*/
|
|
11
|
+
const DeleteTransferDocumentRequestSchema = z.object({
|
|
12
|
+
force: queryBooleanSchema,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const DeleteTransferDocumentResponseSchema = z.object({
|
|
16
|
+
message: z.string().optional(),
|
|
17
|
+
data: z.object({
|
|
18
|
+
success: z.boolean(),
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export namespace DeleteTransferDocumentContractCommand {
|
|
23
|
+
export const RequestSchema = DeleteTransferDocumentRequestSchema;
|
|
24
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
25
|
+
|
|
26
|
+
export const ResponseSchema = DeleteTransferDocumentResponseSchema;
|
|
27
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
28
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TransferDocumentSchema } from '../../schemas/transfer-document/transfer-document.schema';
|
|
3
|
+
|
|
4
|
+
const GetTransferDocumentListRequestSchema = z.object({
|
|
5
|
+
page: z.string().transform(value => Number(value) || 1),
|
|
6
|
+
count: z.string().transform(value => Number(value) || 10),
|
|
7
|
+
searchQuery: z.string().optional(),
|
|
8
|
+
clientUUID: z.uuid().optional(),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const GetTransferDocumentListResponseSchema = z.object({
|
|
12
|
+
message: z.string().optional(),
|
|
13
|
+
data: z.object({
|
|
14
|
+
list: TransferDocumentSchema.array(),
|
|
15
|
+
total: z.number(),
|
|
16
|
+
}),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export namespace GetTransferDocumentListContractQuery {
|
|
20
|
+
export const RequestSchema = GetTransferDocumentListRequestSchema;
|
|
21
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
22
|
+
|
|
23
|
+
export const ResponseSchema = GetTransferDocumentListResponseSchema;
|
|
24
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TransferDocumentDetailedSchema } from '../../schemas/transfer-document/transfer-document-detailed.schema';
|
|
3
|
+
|
|
4
|
+
const GetTransferDocumentRequestSchema = z.object({});
|
|
5
|
+
|
|
6
|
+
const GetTransferDocumentResponseSchema = z.object({
|
|
7
|
+
message: z.string().optional(),
|
|
8
|
+
data: TransferDocumentDetailedSchema,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
export namespace GetTransferDocumentContractQuery {
|
|
12
|
+
export const RequestSchema = GetTransferDocumentRequestSchema;
|
|
13
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
14
|
+
|
|
15
|
+
export const ResponseSchema = GetTransferDocumentResponseSchema;
|
|
16
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TransferDocumentDetailedSchema } from '../../schemas/transfer-document/transfer-document-detailed.schema';
|
|
3
|
+
|
|
4
|
+
// Перевод документа в состояние ISSUED — «передан контрагенту». Дальше он удаляется только
|
|
5
|
+
// с явным подтверждением: восстановить его нельзя, а номер сгорает.
|
|
6
|
+
const IssueTransferDocumentRequestSchema = z.object({});
|
|
7
|
+
|
|
8
|
+
const IssueTransferDocumentResponseSchema = z.object({
|
|
9
|
+
message: z.string().optional(),
|
|
10
|
+
data: TransferDocumentDetailedSchema,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export namespace IssueTransferDocumentContractCommand {
|
|
14
|
+
export const RequestSchema = IssueTransferDocumentRequestSchema;
|
|
15
|
+
export type Request = z.infer<typeof RequestSchema>;
|
|
16
|
+
|
|
17
|
+
export const ResponseSchema = IssueTransferDocumentResponseSchema;
|
|
18
|
+
export type Response = z.infer<typeof ResponseSchema>;
|
|
19
|
+
}
|
|
@@ -8,6 +8,7 @@ export const ErrorI18nKey = {
|
|
|
8
8
|
mergeOrderHasWriteOffs: 'mergeOrder.hasWriteOffs',
|
|
9
9
|
mergeOrderHasDistribution: 'mergeOrder.hasDistribution',
|
|
10
10
|
mergeOrderHasPaymentInvoice: 'mergeOrder.hasPaymentInvoice',
|
|
11
|
+
mergeOrderHasTransferDocument: 'mergeOrder.hasTransferDocument',
|
|
11
12
|
mergeOrderPaymentsTransfer: 'mergeOrder.paymentsTransfer',
|
|
12
13
|
mergeOrderDeliveryMerge: 'mergeOrder.deliveryMerge',
|
|
13
14
|
mergeOrderDeliveryTransfer: 'mergeOrder.deliveryTransfer',
|
package/constant/error.ts
CHANGED
|
@@ -409,6 +409,13 @@ export const ERRORS = {
|
|
|
409
409
|
message: 'Order not deleted, the order is included in a payment invoice',
|
|
410
410
|
httpCode: 409,
|
|
411
411
|
},
|
|
412
|
+
// Отказ общий для удаления заказа и для вывода его из COMPLETED, поэтому формулировка
|
|
413
|
+
// без привязки к действию: «not deleted» вводило бы в заблуждение при смене статуса.
|
|
414
|
+
ORDER_IN_TRANSFER_DOCUMENT: {
|
|
415
|
+
code: 'O059',
|
|
416
|
+
message: 'The order is included in a transfer document and cannot be changed or deleted',
|
|
417
|
+
httpCode: 409,
|
|
418
|
+
},
|
|
412
419
|
ORDER_SPLIT_NOT_COMPLETELY_ERROR: { code: 'O019', message: 'Error splitting orders, not all orders were split', httpCode: 500 },
|
|
413
420
|
ORDER_TOTAL_COST_NEGATIVE: { code: 'O020', message: 'Order total cost is negative', httpCode: 400 },
|
|
414
421
|
ORDER_SUBTOTAL_NEGATIVE: { code: 'O021', message: 'Order subtotal is negative', httpCode: 400 },
|
|
@@ -423,6 +430,7 @@ export const ERRORS = {
|
|
|
423
430
|
ORDER_MERGE_HAS_WRITE_OFFS: { code: 'O031', message: 'Order has write-offs', httpCode: 400 },
|
|
424
431
|
ORDER_MERGE_HAS_DISTRIBUTION: { code: 'O032', message: 'Order has products with distribution', httpCode: 400 },
|
|
425
432
|
ORDER_MERGE_HAS_PAYMENT_INVOICE: { code: 'O040', message: 'Order is included in a payment invoice', httpCode: 400 },
|
|
433
|
+
ORDER_MERGE_HAS_TRANSFER_DOCUMENT: { code: 'O060', message: 'Order is included in a transfer document', httpCode: 400 },
|
|
426
434
|
ORDER_MERGE_BALANCE_STATUS_NOT_ALLOWED: {
|
|
427
435
|
code: 'O033',
|
|
428
436
|
message: 'Order status is balance affecting, merge not allowed',
|
|
@@ -1185,6 +1193,7 @@ export const ERRORS = {
|
|
|
1185
1193
|
REPORT_FETCH_FAILED: { code: 'REP001', message: 'Failed to fetch report', httpCode: 500 },
|
|
1186
1194
|
REPORT_EXPORT_FAILED: { code: 'REP002', message: 'Failed to export report', httpCode: 500 },
|
|
1187
1195
|
REPORT_NO_DATA: { code: 'REP003', message: 'No data available for the selected period', httpCode: 404 },
|
|
1196
|
+
WRITE_OFF_SUMMARY_REPORT_FAILED: { code: 'REP004', message: 'Failed to build write-off summary report', httpCode: 500 },
|
|
1188
1197
|
STATEMENT_PERIOD_TOO_LONG: { code: 'REP004', message: 'Statement period must not exceed 1 year', httpCode: 400 },
|
|
1189
1198
|
|
|
1190
1199
|
// PAYMENT INVOICE
|
|
@@ -1518,4 +1527,49 @@ export const ERRORS = {
|
|
|
1518
1527
|
message: 'Failed to assign cash flow item to transactions',
|
|
1519
1528
|
httpCode: 500,
|
|
1520
1529
|
},
|
|
1530
|
+
TRANSFER_DOCUMENT_CREATE_FAILED: { code: 'TDOC001', message: 'Failed to create transfer document', httpCode: 500 },
|
|
1531
|
+
TRANSFER_DOCUMENT_NOT_FOUND: { code: 'TDOC002', message: 'Transfer document not found', httpCode: 404 },
|
|
1532
|
+
TRANSFER_DOCUMENT_FETCH_FAILED: { code: 'TDOC003', message: 'Failed to fetch transfer documents', httpCode: 500 },
|
|
1533
|
+
TRANSFER_DOCUMENT_DELETE_FAILED: { code: 'TDOC004', message: 'Failed to delete transfer document', httpCode: 500 },
|
|
1534
|
+
TRANSFER_DOCUMENT_ORDERS_REQUIRED: { code: 'TDOC005', message: 'At least one order is required', httpCode: 400 },
|
|
1535
|
+
TRANSFER_DOCUMENT_ORDERS_NOT_FOUND: {
|
|
1536
|
+
code: 'TDOC006',
|
|
1537
|
+
message: 'Some of the requested orders were not found for this client',
|
|
1538
|
+
httpCode: 404,
|
|
1539
|
+
},
|
|
1540
|
+
TRANSFER_DOCUMENT_ORDER_NOT_COMPLETED: {
|
|
1541
|
+
code: 'TDOC007',
|
|
1542
|
+
message: 'A transfer document can only be issued for completed orders',
|
|
1543
|
+
httpCode: 409,
|
|
1544
|
+
},
|
|
1545
|
+
TRANSFER_DOCUMENT_ORDER_ALREADY_ISSUED: {
|
|
1546
|
+
code: 'TDOC008',
|
|
1547
|
+
message: 'Some of the requested orders are already included in another transfer document',
|
|
1548
|
+
httpCode: 409,
|
|
1549
|
+
},
|
|
1550
|
+
TRANSFER_DOCUMENT_AMOUNT_INVALID: { code: 'TDOC009', message: 'Transfer document amount must be greater than zero', httpCode: 400 },
|
|
1551
|
+
TRANSFER_DOCUMENT_EXPORT_FAILED: { code: 'TDOC010', message: 'Failed to build transfer document file', httpCode: 500 },
|
|
1552
|
+
TRANSFER_DOCUMENT_VAT_NOT_SUPPORTED: {
|
|
1553
|
+
code: 'TDOC011',
|
|
1554
|
+
message: 'Transfer documents are only issued as an act (status 2); VAT payers are not supported yet',
|
|
1555
|
+
httpCode: 409,
|
|
1556
|
+
},
|
|
1557
|
+
// Реквизиты сторон проверяем до выпуска: движок считает пустое значение штатным и напечатал бы
|
|
1558
|
+
// документ без «Продавца», ИНН и подписи — недействительный, и компания узнала бы об этом
|
|
1559
|
+
// от контрагента. `errorData` перечисляет незаполненные поля, чтобы UI назвал их поимённо.
|
|
1560
|
+
TRANSFER_DOCUMENT_SELLER_REQUISITES_MISSING: {
|
|
1561
|
+
code: 'TDOC012',
|
|
1562
|
+
message: 'Seller requisites are not filled in company settings',
|
|
1563
|
+
httpCode: 400,
|
|
1564
|
+
},
|
|
1565
|
+
TRANSFER_DOCUMENT_BUYER_REQUISITES_MISSING: {
|
|
1566
|
+
code: 'TDOC014',
|
|
1567
|
+
message: 'Buyer requisites are not filled in the client legal profile',
|
|
1568
|
+
httpCode: 400,
|
|
1569
|
+
},
|
|
1570
|
+
TRANSFER_DOCUMENT_NUMBER_START_DECREASED: {
|
|
1571
|
+
code: 'TDOC013',
|
|
1572
|
+
message: 'Transfer document number start cannot be decreased',
|
|
1573
|
+
httpCode: 400,
|
|
1574
|
+
},
|
|
1521
1575
|
} as const;
|
package/constant/index.ts
CHANGED
|
@@ -5,5 +5,7 @@ export * from './import.constant';
|
|
|
5
5
|
export * from './validation-i18n-key';
|
|
6
6
|
export * from './validation-i18n-message';
|
|
7
7
|
export * from './report.constant';
|
|
8
|
+
export * from './oksm';
|
|
9
|
+
export * from './okei';
|
|
8
10
|
export * from './contact-phone.constant';
|
|
9
11
|
export * from './settings.constant';
|
package/constant/okei.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SalesUnitEnum } from '../enum/sales-unit.enum';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ОКЕИ (ОК 015-94) — общероссийский классификатор единиц измерения. Код идёт в графу 2 УПД,
|
|
5
|
+
* условное национальное обозначение — в графу 2а.
|
|
6
|
+
*
|
|
7
|
+
* Услуги и доставка печатаются как «шт»: отдельной единицы для услуги в ОКЕИ нет, а оставлять
|
|
8
|
+
* графы пустыми при статусе 1 нельзя.
|
|
9
|
+
*/
|
|
10
|
+
export const OKEI_BY_SALES_UNIT: Readonly<Record<SalesUnitEnum, { code: string; name: string }>> = {
|
|
11
|
+
[SalesUnitEnum.PIECE]: { code: '796', name: 'шт' },
|
|
12
|
+
[SalesUnitEnum.PACK]: { code: '778', name: 'упак' },
|
|
13
|
+
[SalesUnitEnum.BOX]: { code: '812', name: 'ящик' },
|
|
14
|
+
};
|
package/constant/oksm.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ОКСМ (ОК 025-2001) — общероссийский классификатор стран мира. Цифровой код идёт в графу 10
|
|
3
|
+
* УПД, краткое наименование — в графу 10а. Коды совпадают с ISO 3166-1 numeric.
|
|
4
|
+
*
|
|
5
|
+
* Список неполный намеренно: здесь страны происхождения, реально встречающиеся у цветочного опта,
|
|
6
|
+
* плюс основные торговые партнёры. Новая страна добавляется сюда, её написания — в OKSM_ALIAS.
|
|
7
|
+
*/
|
|
8
|
+
export const OKSM = [
|
|
9
|
+
{ code: '643', name: 'Россия', alpha2: 'RU' },
|
|
10
|
+
{ code: '528', name: 'Нидерланды', alpha2: 'NL' },
|
|
11
|
+
{ code: '218', name: 'Эквадор', alpha2: 'EC' },
|
|
12
|
+
{ code: '170', name: 'Колумбия', alpha2: 'CO' },
|
|
13
|
+
{ code: '404', name: 'Кения', alpha2: 'KE' },
|
|
14
|
+
{ code: '231', name: 'Эфиопия', alpha2: 'ET' },
|
|
15
|
+
{ code: '834', name: 'Танзания', alpha2: 'TZ' },
|
|
16
|
+
{ code: '800', name: 'Уганда', alpha2: 'UG' },
|
|
17
|
+
{ code: '716', name: 'Зимбабве', alpha2: 'ZW' },
|
|
18
|
+
{ code: '710', name: 'Южная Африка', alpha2: 'ZA' },
|
|
19
|
+
{ code: '376', name: 'Израиль', alpha2: 'IL' },
|
|
20
|
+
{ code: '380', name: 'Италия', alpha2: 'IT' },
|
|
21
|
+
{ code: '792', name: 'Турция', alpha2: 'TR' },
|
|
22
|
+
{ code: '156', name: 'Китай', alpha2: 'CN' },
|
|
23
|
+
{ code: '764', name: 'Таиланд', alpha2: 'TH' },
|
|
24
|
+
{ code: '704', name: 'Вьетнам', alpha2: 'VN' },
|
|
25
|
+
{ code: '356', name: 'Индия', alpha2: 'IN' },
|
|
26
|
+
{ code: '144', name: 'Шри-Ланка', alpha2: 'LK' },
|
|
27
|
+
{ code: '458', name: 'Малайзия', alpha2: 'MY' },
|
|
28
|
+
{ code: '360', name: 'Индонезия', alpha2: 'ID' },
|
|
29
|
+
{ code: '188', name: 'Коста-Рика', alpha2: 'CR' },
|
|
30
|
+
{ code: '484', name: 'Мексика', alpha2: 'MX' },
|
|
31
|
+
{ code: '076', name: 'Бразилия', alpha2: 'BR' },
|
|
32
|
+
{ code: '604', name: 'Перу', alpha2: 'PE' },
|
|
33
|
+
{ code: '152', name: 'Чили', alpha2: 'CL' },
|
|
34
|
+
{ code: '840', name: 'Соединённые Штаты', alpha2: 'US' },
|
|
35
|
+
{ code: '554', name: 'Новая Зеландия', alpha2: 'NZ' },
|
|
36
|
+
{ code: '036', name: 'Австралия', alpha2: 'AU' },
|
|
37
|
+
{ code: '276', name: 'Германия', alpha2: 'DE' },
|
|
38
|
+
{ code: '616', name: 'Польша', alpha2: 'PL' },
|
|
39
|
+
{ code: '056', name: 'Бельгия', alpha2: 'BE' },
|
|
40
|
+
{ code: '250', name: 'Франция', alpha2: 'FR' },
|
|
41
|
+
{ code: '724', name: 'Испания', alpha2: 'ES' },
|
|
42
|
+
{ code: '620', name: 'Португалия', alpha2: 'PT' },
|
|
43
|
+
{ code: '208', name: 'Дания', alpha2: 'DK' },
|
|
44
|
+
{ code: '246', name: 'Финляндия', alpha2: 'FI' },
|
|
45
|
+
{ code: '752', name: 'Швеция', alpha2: 'SE' },
|
|
46
|
+
{ code: '578', name: 'Норвегия', alpha2: 'NO' },
|
|
47
|
+
{ code: '826', name: 'Соединённое Королевство', alpha2: 'GB' },
|
|
48
|
+
{ code: '756', name: 'Швейцария', alpha2: 'CH' },
|
|
49
|
+
{ code: '040', name: 'Австрия', alpha2: 'AT' },
|
|
50
|
+
{ code: '203', name: 'Чехия', alpha2: 'CZ' },
|
|
51
|
+
{ code: '440', name: 'Литва', alpha2: 'LT' },
|
|
52
|
+
{ code: '428', name: 'Латвия', alpha2: 'LV' },
|
|
53
|
+
{ code: '233', name: 'Эстония', alpha2: 'EE' },
|
|
54
|
+
{ code: '112', name: 'Беларусь', alpha2: 'BY' },
|
|
55
|
+
{ code: '398', name: 'Казахстан', alpha2: 'KZ' },
|
|
56
|
+
{ code: '860', name: 'Узбекистан', alpha2: 'UZ' },
|
|
57
|
+
{ code: '051', name: 'Армения', alpha2: 'AM' },
|
|
58
|
+
{ code: '031', name: 'Азербайджан', alpha2: 'AZ' },
|
|
59
|
+
{ code: '268', name: 'Грузия', alpha2: 'GE' },
|
|
60
|
+
{ code: '498', name: 'Молдова', alpha2: 'MD' },
|
|
61
|
+
{ code: '804', name: 'Украина', alpha2: 'UA' },
|
|
62
|
+
{ code: '818', name: 'Египет', alpha2: 'EG' },
|
|
63
|
+
{ code: '504', name: 'Марокко', alpha2: 'MA' },
|
|
64
|
+
{ code: '788', name: 'Тунис', alpha2: 'TN' },
|
|
65
|
+
{ code: '784', name: 'Объединённые Арабские Эмираты', alpha2: 'AE' },
|
|
66
|
+
{ code: '364', name: 'Иран', alpha2: 'IR' },
|
|
67
|
+
{ code: '392', name: 'Япония', alpha2: 'JP' },
|
|
68
|
+
{ code: '410', name: 'Республика Корея', alpha2: 'KR' },
|
|
69
|
+
] as const;
|
|
@@ -4,3 +4,12 @@
|
|
|
4
4
|
* с массивом в тысячи элементов.
|
|
5
5
|
*/
|
|
6
6
|
export const REPORT_EXCLUDE_CLIENT_LIMIT = 500;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Сколько клиентов отдаётся в разрезе списаний по умолчанию и максимум. Итоги считаются по всем
|
|
10
|
+
* строкам независимо от лимита, поэтому усечение влияет только на список; отличить усечённый
|
|
11
|
+
* ответ от полного позволяет `rowsTotal`.
|
|
12
|
+
*/
|
|
13
|
+
export const REPORT_WRITE_OFF_CLIENT_LIMIT_DEFAULT = 50;
|
|
14
|
+
|
|
15
|
+
export const REPORT_WRITE_OFF_CLIENT_LIMIT_MAX = 500;
|
package/enum/index.ts
CHANGED
|
@@ -100,3 +100,8 @@ export * from './payment-invoice-status.enum';
|
|
|
100
100
|
export * from './order-by.enum';
|
|
101
101
|
export * from './report-sort-by.enum';
|
|
102
102
|
export * from './report-order-date-basis.enum';
|
|
103
|
+
export * from './invoice-product-field.enum';
|
|
104
|
+
export * from './transfer-document-state.enum';
|
|
105
|
+
export * from './transfer-document-kind.enum';
|
|
106
|
+
export * from './transfer-document-item-kind.enum';
|
|
107
|
+
export * from './write-off-report-date-basis.enum';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Поля товара, из которых собирается его наименование в документах (накладная, УПД).
|
|
3
|
+
* Порядок значений в настройке = порядок элементов в строке.
|
|
4
|
+
*/
|
|
5
|
+
export enum InvoiceProductFieldEnum {
|
|
6
|
+
CATEGORY = 'CATEGORY',
|
|
7
|
+
NAME = 'NAME',
|
|
8
|
+
GROWER = 'GROWER',
|
|
9
|
+
SIZE = 'SIZE',
|
|
10
|
+
SIZE2 = 'SIZE2',
|
|
11
|
+
COLOR = 'COLOR',
|
|
12
|
+
COUNTRY = 'COUNTRY',
|
|
13
|
+
ARTICLE = 'ARTICLE',
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Природа строки табличной части УПД.
|
|
3
|
+
*
|
|
4
|
+
* По ней билдер понимает, где ставить прочерки в графах страны происхождения и номера ДТ:
|
|
5
|
+
* у услуги и доставки их нет.
|
|
6
|
+
*/
|
|
7
|
+
export enum TransferDocumentItemKindEnum {
|
|
8
|
+
PRODUCT = 'PRODUCT',
|
|
9
|
+
SERVICE = 'SERVICE',
|
|
10
|
+
DELIVERY = 'DELIVERY',
|
|
11
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* По какой дате списание попадает в период отчёта.
|
|
3
|
+
*
|
|
4
|
+
* `WRITE_OFF_DATE` — дата самого списания. На ней живёт блок списаний вкладки «По продажам»:
|
|
5
|
+
* выручка там считается по дате заказа, поэтому списание, оформленное в июле по июньскому
|
|
6
|
+
* заказу, уменьшит операционную прибыль июля. Это осознанное допущение, оно подписано в UI.
|
|
7
|
+
*
|
|
8
|
+
* `CONSIGNMENT_DELIVERY_DATE` — дата поставки партии. На ней построен `/report/profit`, поэтому
|
|
9
|
+
* на этой оси итоги сходятся с его строками «Всего списано» и «Списано по заказам».
|
|
10
|
+
*/
|
|
11
|
+
export enum WriteOffReportDateBasisEnum {
|
|
12
|
+
WRITE_OFF_DATE = 'WRITE_OFF_DATE',
|
|
13
|
+
CONSIGNMENT_DELIVERY_DATE = 'CONSIGNMENT_DELIVERY_DATE',
|
|
14
|
+
}
|
package/package.json
CHANGED
package/schemas/index.ts
CHANGED
|
@@ -81,3 +81,5 @@ export * from './money.schema';
|
|
|
81
81
|
export * from './non-negative-money.schema';
|
|
82
82
|
export * from './positive-money.schema';
|
|
83
83
|
export * from './report/report-order-filter.schema';
|
|
84
|
+
export * from './transfer-document/transfer-document.schema';
|
|
85
|
+
export * from './transfer-document/transfer-document-detailed.schema';
|