From 0ff1643633b0193d6aed74321376fb75bc343419 Mon Sep 17 00:00:00 2001 From: ant Date: Tue, 21 Jul 2026 08:43:57 +0000 Subject: [PATCH 1/3] =?UTF-8?q?[598-51][@ant]=20feat:=20=D0=BF=D0=BE=D1=81?= =?UTF-8?q?=D1=87=D0=B8=D1=82=D0=B0=D1=82=D1=8C=20=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D1=83=D1=8E=20=D1=81=D1=83=D0=BC=D0=BC=D1=83=20=D0=B7=D0=B0?= =?UTF-8?q?=D0=BA=D0=B0=D0=B7=D0=B0=20=D0=BD=D0=B0=20=D0=B1=D1=8D=D0=BA?= =?UTF-8?q?=D0=B5=20=D0=B8=20=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=83=D1=82=D0=B5=D1=87=D0=BA=D1=83=20unknown-?= =?UTF-8?q?=D1=82=D0=B8=D0=BF=D0=BE=D0=B2=20=D0=B8=D0=B7=20GraphQL=20ID-?= =?UTF-8?q?=D1=81=D0=BA=D0=B0=D0=BB=D1=8F=D1=80=D0=B0=20=E2=80=94=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BA=D0=B0=D0=B7=D1=87=D0=B8=D0=BA=D1=83=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BA=D0=B0=D0=B7=D1=8B=D0=B2=D0=B0=D0=BB=D0=B8=20=D1=81=D0=B5?= =?UTF-8?q?=D0=B1=D0=B5=D1=81=D1=82=D0=BE=D0=B8=D0=BC=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B1=D0=B5=D0=B7=20=D0=B2=D0=B7=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D0=B0=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20total=5Fcost+me?= =?UTF-8?q?mbership=5Ffee,=20=D0=B0=20=D0=BE=D1=82=D1=81=D1=83=D1=82=D1=81?= =?UTF-8?q?=D1=82=D0=B2=D0=B8=D0=B5=20scalar-=D0=BC=D0=B0=D0=BF=D0=BF?= =?UTF-8?q?=D0=B8=D0=BD=D0=B3=D0=B0=20=D1=83=20Zeus=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20@Field(()=20=3D>=20ID)=20=D0=B4=D0=B0=D0=B2=D0=B0=D0=BB?= =?UTF-8?q?=D0=BE=20unknown=20=D0=BD=D0=B0=20=D1=84=D1=80=D0=BE=D0=BD?= =?UTF-8?q?=D1=82=D0=B5=20=D0=B2=D0=B5=D0=B7=D0=B4=D0=B5,=20=D0=B3=D0=B4?= =?UTF-8?q?=D0=B5=20DTO=20=D0=BE=D0=B1=D1=8A=D1=8F=D0=B2=D0=BB=D1=8F=D0=BB?= =?UTF-8?q?=D0=B8=20id-=D0=BF=D0=BE=D0=BB=D1=8F=20=D1=87=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=B7=20ID=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20String?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../dto/marketplace-apl-reception.dto.ts | 18 +- .../dto/marketplace-inventory.dto.ts | 26 +- .../application/dto/marketplace-order.dto.ts | 30 +- .../dto/marketplace-outgoing-payment.dto.ts | 10 +- .../dto/marketplace-shipment.dto.ts | 18 +- .../application/dto/marketplace-stock.dto.ts | 26 +- .../entities/marketplace-order.entity.spec.ts | 16 +- .../entities/marketplace-order.entity.ts | 8 + .../entities/marketplace-order.types.ts | 8 + .../marketplace-order-repository.adapter.ts | 55 +++- .../entities/marketplace-order.entity.ts | 9 + .../mappers/marketplace-order-delta.mapper.ts | 17 + .../mappers/marketplace-order.mapper.ts | 1 + components/controller/zeus/const.ts | 44 +-- components/controller/zeus/index.ts | 300 +++++++++--------- .../selectors/marketplace/orderSelector.ts | 2 + components/sdk/src/zeus/const.ts | 44 +-- components/sdk/src/zeus/index.ts | 300 +++++++++--------- 18 files changed, 535 insertions(+), 397 deletions(-) diff --git a/components/controller/src/extensions/marketplace/application/dto/marketplace-apl-reception.dto.ts b/components/controller/src/extensions/marketplace/application/dto/marketplace-apl-reception.dto.ts index a7e36ca4f1e..a6f0c42304a 100644 --- a/components/controller/src/extensions/marketplace/application/dto/marketplace-apl-reception.dto.ts +++ b/components/controller/src/extensions/marketplace/application/dto/marketplace-apl-reception.dto.ts @@ -1,4 +1,4 @@ -import { Field, ID, InputType, Int, ObjectType, registerEnumType } from '@nestjs/graphql'; +import { Field, InputType, Int, ObjectType, registerEnumType } from '@nestjs/graphql'; import { ArrayMinSize, IsArray, IsInt, IsNotEmpty, IsOptional, IsString, Min, ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; import type { MarketplaceAplReceptionDomainEntity } from '../../domain/entities/marketplace-apl-reception.entity'; @@ -29,7 +29,7 @@ registerEnumType(MarketplaceAplReceptionStatusEnum, { @ObjectType('MarketplaceAplReceptionFactEntry') export class MarketplaceAplReceptionFactEntryDTO { - @Field(() => ID) + @Field(() => String) order_id!: string; @Field(() => Int, { description: 'Фактически принятое количество (для расхождений Варианта Б).' }) @@ -56,7 +56,7 @@ export class MarketplaceAplReceptionFactEntryDTO { @InputType('MarketplaceAplReceptionFactEntryInput') export class MarketplaceAplReceptionFactEntryInputDTO { - @Field(() => ID) + @Field(() => String) @IsString() @IsNotEmpty() order_id!: string; @@ -77,16 +77,16 @@ export class MarketplaceAplReceptionFactEntryInputDTO { @ObjectType('MarketplaceAplReception') export class MarketplaceAplReceptionDTO { - @Field(() => ID) + @Field(() => String) id!: string; @Field(() => String) coopname!: string; - @Field(() => ID, { description: 'Партия поставки, по которой формируется приёмка.' }) + @Field(() => String, { description: 'Партия поставки, по которой формируется приёмка.' }) shipment_id!: string; - @Field(() => ID, { description: 'Консолидированная заявка.' }) + @Field(() => String, { description: 'Консолидированная заявка.' }) cycle_id!: string; @Field(() => String, { description: 'КУ-получатель партии.' }) @@ -154,7 +154,7 @@ export class MarketplaceAplReceptionDTO { @InputType('MarketplaceCreateAplReceptionInput') export class MarketplaceCreateAplReceptionInputDTO { - @Field(() => ID, { description: 'Партия поставки в статусе SUPPLY_PREPARED.' }) + @Field(() => String, { description: 'Партия поставки в статусе SUPPLY_PREPARED.' }) @IsString() @IsNotEmpty() shipment_id!: string; @@ -173,7 +173,7 @@ export class MarketplaceCreateAplReceptionInputDTO { @InputType('MarketplaceSignAplReceptionInput') export class MarketplaceSignAplReceptionInputDTO { - @Field(() => ID, { description: 'Идентификатор акта приёмки.' }) + @Field(() => String, { description: 'Идентификатор акта приёмки.' }) @IsString() @IsNotEmpty() apl_reception_id!: string; @@ -191,7 +191,7 @@ export class MarketplaceSignAplReceptionInputDTO { @InputType('MarketplaceAplReceptionByIdInput') export class MarketplaceAplReceptionByIdInputDTO { - @Field(() => ID, { description: 'Идентификатор акта приёмки.' }) + @Field(() => String, { description: 'Идентификатор акта приёмки.' }) @IsString() @IsNotEmpty() apl_reception_id!: string; diff --git a/components/controller/src/extensions/marketplace/application/dto/marketplace-inventory.dto.ts b/components/controller/src/extensions/marketplace/application/dto/marketplace-inventory.dto.ts index f4951d27046..512eb210520 100644 --- a/components/controller/src/extensions/marketplace/application/dto/marketplace-inventory.dto.ts +++ b/components/controller/src/extensions/marketplace/application/dto/marketplace-inventory.dto.ts @@ -1,4 +1,4 @@ -import { Field, ID, InputType, Int, ObjectType, registerEnumType } from '@nestjs/graphql'; +import { Field, InputType, Int, ObjectType, registerEnumType } from '@nestjs/graphql'; import { Type } from 'class-transformer'; import { IsArray, @@ -61,7 +61,7 @@ registerEnumType(MarketplaceInventoryStatusEnum, { @ObjectType('MarketplaceInventoryItem') export class MarketplaceInventoryItemDTO { - @Field(() => ID) + @Field(() => String) id!: string; @Field(() => String, { description: 'Кооператив, на складе которого лежит имущество.' }) @@ -76,10 +76,10 @@ export class MarketplaceInventoryItemDTO { @Field(() => MarketplaceBarcodeFormatEnum, { nullable: true }) barcode_format!: MarketplaceBarcodeFormatEnum | null; - @Field(() => ID, { description: 'Заказ, к которому относится позиция.' }) + @Field(() => String, { description: 'Заказ, к которому относится позиция.' }) order_id!: string; - @Field(() => ID, { description: 'Партия поставки, в составе которой имущество получено.' }) + @Field(() => String, { description: 'Партия поставки, в составе которой имущество получено.' }) shipment_id!: string; @Field(() => String, { description: 'КУ-получатель имущества.' }) @@ -159,13 +159,13 @@ export class MarketplaceInventoryItemDTO { }) arrival_price!: string | null; - @Field(() => ID, { + @Field(() => String, { nullable: true, description: 'Предложение кооператива, которым остаток опубликован в каталоге. Пусто — не опубликован.', }) published_offer_id!: string | null; - @Field(() => ID, { + @Field(() => String, { nullable: true, description: 'Заказ со склада кооператива, под который позиция зарезервирована. Пусто — свободна.', }) @@ -180,7 +180,7 @@ export class MarketplaceInventoryItemDTO { @InputType('MarketplaceGenerateInventoryLabelInput') export class MarketplaceGenerateInventoryLabelInputDTO { - @Field(() => ID, { description: 'Позиция склада, на которую наклеивается штрих-код.' }) + @Field(() => String, { description: 'Позиция склада, на которую наклеивается штрих-код.' }) @IsString() @IsNotEmpty() inventory_id!: string; @@ -196,7 +196,7 @@ export class MarketplaceGenerateInventoryLabelInputDTO { @InputType('MarketplaceBindInventoryBarcodeInput') export class MarketplaceBindInventoryBarcodeInputDTO { - @Field(() => ID, { description: 'Позиция склада, к которой привязывается отсканированный штрих-код.' }) + @Field(() => String, { description: 'Позиция склада, к которой привязывается отсканированный штрих-код.' }) @IsString() @IsNotEmpty() inventory_id!: string; @@ -220,7 +220,7 @@ export class MarketplaceBindInventoryBarcodeInputDTO { @InputType('MarketplaceAssignInventoryShelfInput') export class MarketplaceAssignInventoryShelfInputDTO { - @Field(() => ID, { description: 'Позиция склада, для которой назначается полка.' }) + @Field(() => String, { description: 'Позиция склада, для которой назначается полка.' }) @IsString() @IsNotEmpty() inventory_id!: string; @@ -236,7 +236,7 @@ export class MarketplaceAssignInventoryShelfInputDTO { @InputType('MarketplaceClearInventoryLabelInput') export class MarketplaceClearInventoryLabelInputDTO { - @Field(() => ID, { description: 'Позиция склада, с которой снимается штрих-код (для переклейки).' }) + @Field(() => String, { description: 'Позиция склада, с которой снимается штрих-код (для переклейки).' }) @IsString() @IsNotEmpty() inventory_id!: string; @@ -260,7 +260,7 @@ export class MarketplaceInventorySplitEntryInputDTO { @InputType('MarketplaceSplitInventoryInput') export class MarketplaceSplitInventoryInputDTO { - @Field(() => ID, { description: 'Позиция склада, которую раскладывают по нескольким полкам.' }) + @Field(() => String, { description: 'Позиция склада, которую раскладывают по нескольким полкам.' }) @IsString() @IsNotEmpty() inventory_id!: string; @@ -284,12 +284,12 @@ export class MarketplaceInventoryMutationResultDTO { @InputType('MarketplaceListInventoryInput') export class MarketplaceListInventoryInputDTO { - @Field(() => ID, { nullable: true, description: 'Фильтр по заказу.' }) + @Field(() => String, { nullable: true, description: 'Фильтр по заказу.' }) @IsOptional() @IsString() order_id?: string; - @Field(() => ID, { nullable: true, description: 'Фильтр по партии поставки.' }) + @Field(() => String, { nullable: true, description: 'Фильтр по партии поставки.' }) @IsOptional() @IsString() shipment_id?: string; diff --git a/components/controller/src/extensions/marketplace/application/dto/marketplace-order.dto.ts b/components/controller/src/extensions/marketplace/application/dto/marketplace-order.dto.ts index 05cac816f11..1a20e21c2d9 100644 --- a/components/controller/src/extensions/marketplace/application/dto/marketplace-order.dto.ts +++ b/components/controller/src/extensions/marketplace/application/dto/marketplace-order.dto.ts @@ -188,9 +188,24 @@ export class MarketplaceOrderDTO { @Field(() => String, { description: 'Цена за единицу товара на момент заказа.' }) public readonly price_per_unit!: string; - @Field(() => String, { description: 'Общая сумма заказа.' }) + @Field(() => String, { description: 'Общая сумма заказа (стоимость имущества без членского взноса).' }) public readonly total_cost!: string; + @Field(() => String, { + nullable: true, + description: + 'Членский взнос, включённый в стоимость заказа, по ставке на момент оформления. ' + + 'Заказчик платит total_cost + membership_fee; пусто — заказ ещё не подтверждён блокчейном.', + }) + public readonly membership_fee!: string | null; + + @Field(() => String, { + description: + 'Полная сумма к оплате заказчиком: total_cost + membership_fee. Готовое значение — ' + + 'клиенту не нужно складывать поля самому.', + }) + public readonly total_cost_with_fee!: string; + @Field(() => String, { nullable: true, description: 'Идентификатор партии-накопителя, если заказ присоединён.' }) public readonly cycle_id!: string | null; @@ -370,6 +385,17 @@ export interface MarketplaceOrderDisplayFields { warehouse_shelves?: string[] | null; } +/** + * `total_cost`/`membership_fee` — numeric(_, 4) колонки (scale колонки, не + * MARKETPLACE_ASSET_CONFIG.decimals — блокчейн-символ здесь ни при чём, + * складываются уже персистентные PG-значения). Фиксированные 4 знака держат + * результат чистым от плавающей точки на типичных суммах; конечное округление + * до валюты — на клиенте при отображении (formatAsset2Digits и т.п.). + */ +function sumOrderAmounts(total_cost: string, membership_fee: string | null): string { + return (Number.parseFloat(total_cost) + Number.parseFloat(membership_fee ?? '0')).toFixed(4); +} + export function toMarketplaceOrderDTO( o: MarketplaceOrderDomainEntity, display?: MarketplaceOrderDisplayFields @@ -398,6 +424,8 @@ export function toMarketplaceOrderDTO( group_min_volume: display?.group_min_volume ?? null, price_per_unit: o.price_per_unit, total_cost: o.total_cost, + membership_fee: o.membership_fee, + total_cost_with_fee: sumOrderAmounts(o.total_cost, o.membership_fee), cycle_id: o.cycle_id, checkout_id: o.checkout_id, shipment_id: o.shipment_id, diff --git a/components/controller/src/extensions/marketplace/application/dto/marketplace-outgoing-payment.dto.ts b/components/controller/src/extensions/marketplace/application/dto/marketplace-outgoing-payment.dto.ts index 816ee8588ce..9060fb018a8 100644 --- a/components/controller/src/extensions/marketplace/application/dto/marketplace-outgoing-payment.dto.ts +++ b/components/controller/src/extensions/marketplace/application/dto/marketplace-outgoing-payment.dto.ts @@ -1,4 +1,4 @@ -import { Field, ID, InputType, ObjectType, registerEnumType } from '@nestjs/graphql'; +import { Field, InputType, ObjectType, registerEnumType } from '@nestjs/graphql'; import { IsArray, IsEnum, IsOptional, IsString } from 'class-validator'; import type { MarketplaceOutgoingPaymentRequestDomainEntity } from '../../domain/entities/marketplace-outgoing-payment-request.entity'; @@ -50,7 +50,7 @@ export class MarketplaceListOutgoingPaymentsFilterInputDTO { @ObjectType('MarketplaceOutgoingPaymentRequest') export class MarketplaceOutgoingPaymentRequestDTO { - @Field(() => ID) + @Field(() => String) id!: string; @Field(() => String) @@ -61,10 +61,10 @@ export class MarketplaceOutgoingPaymentRequestDTO { }) order_hash!: string; - @Field(() => ID, { description: 'Идентификатор заказа в каталоге поставок.' }) + @Field(() => String, { description: 'Идентификатор заказа в каталоге поставок.' }) order_id!: string; - @Field(() => ID, { description: 'Акт приёмки, по которому возникло обязательство.' }) + @Field(() => String, { description: 'Акт приёмки, по которому возникло обязательство.' }) apl_reception_id!: string; @Field(() => String, { description: 'Аккаунт поставщика — получатель выплаты.' }) @@ -103,7 +103,7 @@ export class MarketplaceOutgoingPaymentRequestDTO { }) payout_tx_hash!: string | null; - @Field(() => ID, { + @Field(() => String, { nullable: true, description: 'Идентификатор связанного платежа в общем реестре кооператива — кассир видит ' + diff --git a/components/controller/src/extensions/marketplace/application/dto/marketplace-shipment.dto.ts b/components/controller/src/extensions/marketplace/application/dto/marketplace-shipment.dto.ts index 5a3891945bb..19f46ea8a39 100644 --- a/components/controller/src/extensions/marketplace/application/dto/marketplace-shipment.dto.ts +++ b/components/controller/src/extensions/marketplace/application/dto/marketplace-shipment.dto.ts @@ -1,4 +1,4 @@ -import { Field, ID, Int, InputType, ObjectType, registerEnumType } from '@nestjs/graphql'; +import { Field, Int, InputType, ObjectType, registerEnumType } from '@nestjs/graphql'; import { IsArray, IsEnum, IsInt, IsNotEmpty, IsOptional, IsString, Min, ValidateNested } from 'class-validator'; import { Type } from 'class-transformer'; import type { MarketplaceShipmentDomainEntity } from '../../domain/entities/marketplace-shipment.entity'; @@ -38,7 +38,7 @@ registerEnumType(MarketplaceShipmentStatusEnum, { // Задаётся при формировании партии; число коробок выводится из количества. @ObjectType('MarketplaceShipmentLinePackaging') export class MarketplaceShipmentLinePackagingDTO { - @Field(() => ID, { description: 'Заказ партии, к которому относится упаковка.' }) + @Field(() => String, { description: 'Заказ партии, к которому относится упаковка.' }) order_id!: string; @Field(() => Int, { description: 'Сколько единиц имущества в одной коробке.' }) units_per_box!: number; @@ -75,7 +75,7 @@ export class MarketplaceShipmentTTNDataDTO { // (для каждого заказа: сколько единиц в коробке). @InputType('MarketplaceShipmentLinePackagingInput') export class MarketplaceShipmentLinePackagingInputDTO { - @Field(() => ID, { description: 'Заказ партии, к которому относится упаковка.' }) + @Field(() => String, { description: 'Заказ партии, к которому относится упаковка.' }) @IsString() @IsNotEmpty() order_id!: string; @@ -131,13 +131,13 @@ export class MarketplaceShipmentTTNDataInputDTO { @ObjectType('MarketplaceShipment') export class MarketplaceShipmentDTO { - @Field(() => ID) + @Field(() => String) id!: string; @Field(() => String, { description: 'Кооператив, в котором сформирована партия.' }) coopname!: string; - @Field(() => ID, { description: 'Идентификатор консолидированной заявки.' }) + @Field(() => String, { description: 'Идентификатор консолидированной заявки.' }) cycle_id!: string; @Field(() => String, { description: 'Account поставщика-владельца Offer\'ов.' }) @@ -195,7 +195,7 @@ export class MarketplaceShipmentGroupInputDTO { @IsEnum(MarketplaceShipmentDeliveryVariantEnum) delivery_variant!: MarketplaceShipmentDeliveryVariantEnum; - @Field(() => [ID], { + @Field(() => [String], { nullable: true, description: 'Подмножество заказов этого КУ, реально погружаемых в партию (частичная отгрузка). ' + @@ -218,7 +218,7 @@ export class MarketplaceShipmentGroupInputDTO { @InputType('MarketplaceCreateShipmentInput') export class MarketplaceCreateShipmentInputDTO { - @Field(() => ID, { description: 'Идентификатор консолидированной заявки в статусе ACCEPTED.' }) + @Field(() => String, { description: 'Идентификатор консолидированной заявки в статусе ACCEPTED.' }) @IsString() @IsNotEmpty() cycle_id!: string; @@ -245,7 +245,7 @@ export class MarketplaceCreateShipmentResultDTO { @InputType('MarketplaceGetShipmentInput') export class MarketplaceGetShipmentInputDTO { - @Field(() => ID, { description: 'Идентификатор партии поставки.' }) + @Field(() => String, { description: 'Идентификатор партии поставки.' }) @IsString() @IsNotEmpty() shipment_id!: string; @@ -253,7 +253,7 @@ export class MarketplaceGetShipmentInputDTO { @InputType('MarketplaceListShipmentsInput') export class MarketplaceListShipmentsInputDTO { - @Field(() => ID, { nullable: true, description: 'Фильтр по консолидированной заявке.' }) + @Field(() => String, { nullable: true, description: 'Фильтр по консолидированной заявке.' }) @IsOptional() @IsString() cycle_id?: string; diff --git a/components/controller/src/extensions/marketplace/application/dto/marketplace-stock.dto.ts b/components/controller/src/extensions/marketplace/application/dto/marketplace-stock.dto.ts index e54c6865512..016b9e58242 100644 --- a/components/controller/src/extensions/marketplace/application/dto/marketplace-stock.dto.ts +++ b/components/controller/src/extensions/marketplace/application/dto/marketplace-stock.dto.ts @@ -1,4 +1,4 @@ -import { Field, ID, InputType, Int, ObjectType, registerEnumType } from '@nestjs/graphql'; +import { Field, InputType, Int, ObjectType, registerEnumType } from '@nestjs/graphql'; import { Type } from 'class-transformer'; import { ArrayNotEmpty, @@ -31,7 +31,7 @@ registerEnumType(MarketplaceStockProposalStatusEnum, { @InputType('MarketplacePublishStockInput') export class MarketplacePublishStockInputDTO { - @Field(() => [ID], { description: 'Позиции свободного остатка склада для публикации в каталог.' }) + @Field(() => [String], { description: 'Позиции свободного остатка склада для публикации в каталог.' }) @IsArray() @ArrayNotEmpty() @IsString({ each: true }) @@ -49,7 +49,7 @@ export class MarketplacePublishStockInputDTO { @InputType('MarketplaceUnpublishStockInput') export class MarketplaceUnpublishStockInputDTO { - @Field(() => [ID], { description: 'Опубликованные позиции остатка, снимаемые с витрины.' }) + @Field(() => [String], { description: 'Опубликованные позиции остатка, снимаемые с витрины.' }) @IsArray() @ArrayNotEmpty() @IsString({ each: true }) @@ -64,7 +64,7 @@ export class MarketplaceUnpublishStockResultDTO { @InputType('MarketplaceStockProposalItemInput') export class MarketplaceStockProposalItemInputDTO { - @Field(() => ID, { description: 'Предложение кооператива из опубликованного остатка.' }) + @Field(() => String, { description: 'Предложение кооператива из опубликованного остатка.' }) @IsString() @IsNotEmpty() offer_id!: string; @@ -99,7 +99,7 @@ export class MarketplaceStockIssuancePrepareInputDTO { @ObjectType('MarketplaceStockIssuanceOperatorLine') export class MarketplaceStockIssuanceOperatorLineDTO { - @Field(() => ID, { description: 'Предложение кооператива из остатка.' }) + @Field(() => String, { description: 'Предложение кооператива из остатка.' }) offer_id!: string; @Field(() => Int, { description: 'Количество единиц.' }) @@ -122,7 +122,7 @@ export class MarketplaceStockIssuanceOperatorLineDTO { @InputType('MarketplaceCreateStockProposalLineInput') export class MarketplaceCreateStockProposalLineInputDTO { - @Field(() => ID, { description: 'Предложение кооператива из остатка.' }) + @Field(() => String, { description: 'Предложение кооператива из остатка.' }) @IsString() @IsNotEmpty() offer_id!: string; @@ -147,7 +147,7 @@ export class MarketplaceCreateStockProposalLineInputDTO { @InputType('MarketplaceCreateOrderProposalLineInput') export class MarketplaceCreateOrderProposalLineInputDTO { - @Field(() => ID, { description: 'Существующий заказ пайщика к выдаче этим бандлом.' }) + @Field(() => String, { description: 'Существующий заказ пайщика к выдаче этим бандлом.' }) @IsString() @IsNotEmpty() order_id!: string; @@ -205,7 +205,7 @@ export class MarketplaceCreateStockProposalInputDTO { @InputType('MarketplaceResolveStockProposalInput') export class MarketplaceResolveStockProposalInputDTO { - @Field(() => ID, { description: 'Предложение со склада кооператива.' }) + @Field(() => String, { description: 'Предложение со склада кооператива.' }) @IsString() @IsNotEmpty() proposal_id!: string; @@ -296,7 +296,7 @@ export class MarketplaceFinalizeStockIssuanceInputDTO extends MarketplaceResolve @InputType('MarketplaceCancelStockOrderInput') export class MarketplaceCancelStockOrderInputDTO { - @Field(() => ID, { description: 'Заказ со склада кооператива, отменяемый до открытия выдачи.' }) + @Field(() => String, { description: 'Заказ со склада кооператива, отменяемый до открытия выдачи.' }) @IsString() @IsNotEmpty() order_id!: string; @@ -325,7 +325,7 @@ export class MarketplaceListStockProposalsInputDTO { @ObjectType('MarketplaceStockProposalItem') export class MarketplaceStockProposalItemDTO { - @Field(() => ID, { description: 'Предложение кооператива из остатка.' }) + @Field(() => String, { description: 'Предложение кооператива из остатка.' }) offer_id!: string; @Field(() => Int, { description: 'Предложенное количество единиц.' }) @@ -340,7 +340,7 @@ export class MarketplaceStockProposalItemDTO { @ObjectType('MarketplaceStockProposal') export class MarketplaceStockProposalDTO { - @Field(() => ID) + @Field(() => String) id!: string; @Field(() => String, { description: 'Кооперативный участок, со склада которого предложено имущество.' }) @@ -361,7 +361,7 @@ export class MarketplaceStockProposalDTO { @Field(() => String, { description: 'Итоговая сумма предложения.' }) total_cost!: string; - @Field(() => [ID], { description: 'Заказы, созданные при принятии предложения.' }) + @Field(() => [String], { description: 'Заказы, созданные при принятии предложения.' }) created_order_ids!: string[]; @Field(() => Date, { nullable: true, description: 'Момент решения по предложению.' }) @@ -376,7 +376,7 @@ export class MarketplaceStockProposalAcceptResultDTO { @Field(() => MarketplaceStockProposalDTO) proposal!: MarketplaceStockProposalDTO; - @Field(() => [ID], { description: 'Созданные заказы со склада кооператива.' }) + @Field(() => [String], { description: 'Созданные заказы со склада кооператива.' }) order_ids!: string[]; } diff --git a/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.entity.spec.ts b/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.entity.spec.ts index 50a0676011d..1968d7ecb74 100644 --- a/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.entity.spec.ts +++ b/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.entity.spec.ts @@ -14,6 +14,7 @@ function buildProps(overrides: Partial = {}): Marketplace quantity: 3, price_per_unit: '150.0000', total_cost: '450.0000', + membership_fee: null, cycle_id: null, checkout_id: null, shipment_id: null, @@ -87,6 +88,7 @@ describe('MarketplaceOrderDomainEntity', () => { order_hash: 'c'.repeat(64), // другой hash on_chain_id: '99', status: 'ACTIVE', + membership_fee: null, }, 1_000_000, true @@ -106,6 +108,7 @@ describe('MarketplaceOrderDomainEntity', () => { order_hash: 'a'.repeat(64), on_chain_id: '101', status: 'ACCEPTED', + membership_fee: null, }, 2_000_000, true @@ -164,7 +167,7 @@ describe('MarketplaceOrderDomainEntity', () => { const order = new MarketplaceOrderDomainEntity(buildProps({ status: 'ACTIVE' })); order.updateFromBlockchain( - { order_hash: 'a'.repeat(64), on_chain_id: '10', status: 'ACCEPTED' }, + { order_hash: 'a'.repeat(64), on_chain_id: '10', status: 'ACCEPTED', membership_fee: null }, 2_000_000, true ); @@ -178,7 +181,7 @@ describe('MarketplaceOrderDomainEntity', () => { ); order.updateFromBlockchain( - { order_hash: 'a'.repeat(64), on_chain_id: '11', status: 'ACTIVE' }, + { order_hash: 'a'.repeat(64), on_chain_id: '11', status: 'ACTIVE', membership_fee: null }, 2_100_000, true ); @@ -192,7 +195,7 @@ describe('MarketplaceOrderDomainEntity', () => { const order = new MarketplaceOrderDomainEntity(buildProps({ status: 'ACCEPTED' })); order.updateFromBlockchain( - { order_hash: 'a'.repeat(64), on_chain_id: '12', status: 'ACTIVE' }, + { order_hash: 'a'.repeat(64), on_chain_id: '12', status: 'ACTIVE', membership_fee: null }, 2_200_000, true ); @@ -204,7 +207,7 @@ describe('MarketplaceOrderDomainEntity', () => { const order = new MarketplaceOrderDomainEntity(buildProps({ status: 'ACCEPTED' })); order.updateFromBlockchain( - { order_hash: 'a'.repeat(64), on_chain_id: '13', status: 'CANCELLED_BY_ORDERER' }, + { order_hash: 'a'.repeat(64), on_chain_id: '13', status: 'CANCELLED_BY_ORDERER', membership_fee: null }, 2_300_000, false ); @@ -224,7 +227,7 @@ describe('MarketplaceOrderDomainEntity', () => { ); order.updateFromBlockchain( - { order_hash: 'a'.repeat(64), on_chain_id: '20', status: 'ACTIVE' }, + { order_hash: 'a'.repeat(64), on_chain_id: '20', status: 'ACTIVE', membership_fee: null }, 2_500_000, false ); @@ -237,7 +240,7 @@ describe('MarketplaceOrderDomainEntity', () => { const order = new MarketplaceOrderDomainEntity(buildProps({ status: 'RETURNED' })); order.updateFromBlockchain( - { order_hash: 'a'.repeat(64), on_chain_id: '21', status: 'RECEIVED' }, + { order_hash: 'a'.repeat(64), on_chain_id: '21', status: 'RECEIVED', membership_fee: null }, 2_600_000, false ); @@ -255,6 +258,7 @@ describe('MarketplaceOrderDomainEntity', () => { order_hash: 'a'.repeat(64), on_chain_id: '14', status: 'ACCEPTED_PENDING_SUPPLIER_INDIVIDUAL', + membership_fee: null, }, 2_400_000, true diff --git a/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.entity.ts b/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.entity.ts index a62c83c5710..4eda2ebeb8e 100644 --- a/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.entity.ts +++ b/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.entity.ts @@ -36,6 +36,8 @@ export class MarketplaceOrderDomainEntity implements IBlockchainSynchronizable { public readonly quantity: number; public readonly price_per_unit: string; public readonly total_cost: string; + /** Членский взнос, включённый в стоимость заказа — on-chain mirror (см. MarketplaceOrderProps). */ + public membership_fee: string | null; public readonly cycle_id: string | null; /** Грань «заказ заказчика» (Эпик 16): общий id строк одного оформления на один КУ; null = legacy покарточный заказ. */ public readonly checkout_id: string | null; @@ -92,6 +94,7 @@ export class MarketplaceOrderDomainEntity implements IBlockchainSynchronizable { this.quantity = props.quantity; this.price_per_unit = props.price_per_unit; this.total_cost = props.total_cost; + this.membership_fee = props.membership_fee; this.cycle_id = props.cycle_id; this.checkout_id = props.checkout_id; this.shipment_id = props.shipment_id; @@ -157,6 +160,9 @@ export class MarketplaceOrderDomainEntity implements IBlockchainSynchronizable { this.on_chain_id = blockchainData.on_chain_id; this.on_chain_block_num = blockNum; this.on_chain_present = present; + // membership_fee — immutable on-chain snapshot (контракт пишет его один + // раз при createorder), безусловный overwrite идемпотентен. + this.membership_fee = blockchainData.membership_fee; // Forward-only guard. Backend опережает цепь на нескольких переходах // «прямого пути»: cycle-hook / синтез индивидуальной заявки переводят // Order в ACCEPTED_PENDING_SUPPLIER(_INDIVIDUAL) и далее ACCEPTED / @@ -279,4 +285,6 @@ export interface MarketplaceOrderBlockchainData { order_hash: string; on_chain_id: string; status: MarketplaceOrderStatus; + /** Членский взнос из on-chain `order` row (requirement b6), null — старая строка без поля. */ + membership_fee: string | null; } diff --git a/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.types.ts b/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.types.ts index 55ac205e7af..2824e252738 100644 --- a/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.types.ts +++ b/components/controller/src/extensions/marketplace/domain/entities/marketplace-order.types.ts @@ -104,6 +104,14 @@ export interface MarketplaceOrderProps { quantity: number; price_per_unit: string; total_cost: string; + /** + * Членский взнос, включённый в стоимость заказа (requirement b6). On-chain + * mirror — контракт сам считает его при `createorder` по ставке на момент + * заказа; backend не пересчитывает. Null до первой sync-дельты (см. + * `MarketplaceOrderDomainEntity.updateFromBlockchain`) и у заказов, + * созданных до появления поля на контракте (`binary_extension`). + */ + membership_fee: string | null; cycle_id: string | null; /** Грань «заказ заказчика» (Эпик 16): общий id строк одного оформления на один КУ; null = legacy покарточный заказ. */ checkout_id: string | null; diff --git a/components/controller/src/extensions/marketplace/infrastructure/adapters/marketplace-order-repository.adapter.ts b/components/controller/src/extensions/marketplace/infrastructure/adapters/marketplace-order-repository.adapter.ts index e1cc9751d62..b554836be3c 100644 --- a/components/controller/src/extensions/marketplace/infrastructure/adapters/marketplace-order-repository.adapter.ts +++ b/components/controller/src/extensions/marketplace/infrastructure/adapters/marketplace-order-repository.adapter.ts @@ -6,7 +6,10 @@ import { MARKETPLACE_ORDER_STATUS_CHANGED_EVENT, type MarketplaceOrderStatusChangedEvent, } from '../../application/events/marketplace-notification.events'; -import { MarketplaceOrderDomainEntity } from '../../domain/entities/marketplace-order.entity'; +import { + MarketplaceOrderDomainEntity, + type MarketplaceOrderBlockchainData, +} from '../../domain/entities/marketplace-order.entity'; import type { MarketplaceOrderCreateInput, MarketplaceOrderDomainRepository, @@ -226,7 +229,9 @@ export class MarketplaceOrderRepositoryAdapter implements MarketplaceOrderDomain * out-of-band on-chain транзакций. По умолчанию — no-op с warn-логом. */ async createIfNotExists( - blockchainData: { order_hash: string; on_chain_id: string; status: MarketplaceOrderStatus }, + // Типизировано полным MarketplaceOrderBlockchainData (не ad-hoc inline-типом) — + // иначе новое on-chain-поле (как membership_fee) молча не долетает и сюда. + blockchainData: MarketplaceOrderBlockchainData, blockNum: number, present = true ): Promise { @@ -236,6 +241,7 @@ export class MarketplaceOrderRepositoryAdapter implements MarketplaceOrderDomain existing.on_chain_block_num = blockNum; existing.on_chain_present = present; existing.status = blockchainData.status; + existing.membership_fee = blockchainData.membership_fee; return this.persistDomain(existing); } // Out-of-band on-chain Order: оставляем минимальный stub-row, @@ -488,22 +494,41 @@ export class MarketplaceOrderRepositoryAdapter implements MarketplaceOrderDomain // ── private ── + /** + * Поля, которые может изменить `entity.updateFromBlockchain(...)` (sync-flow) + * или ручная мутация в `createIfNotExists`. Именованный Pick-тип — не просто + * документация: если `updateFromBlockchain` начнёт писать новое on-chain + * поле, а сюда его забудут добавить, объект `patch` ниже не покроет тип и + * TS не даст скомпилироваться. Раньше (до фикса membership_fee) + * `repo.update()` принимал произвольный `QueryDeepPartialEntity` без такой + * проверки — поле молча терялось при sync. + */ private async persistDomain( entity: MarketplaceOrderDomainEntity ): Promise { - await this.repo.update( - { id: entity.id }, - { - status: entity.status, - last_status_reason: entity.last_status_reason, - accepted_at: entity.accepted_at, - received_at: entity.received_at, - cancelled_at: entity.cancelled_at, - on_chain_id: entity.on_chain_id, - on_chain_block_num: entity.on_chain_block_num, - on_chain_present: entity.on_chain_present, - } - ); + const patch: Pick< + MarketplaceOrderEntity, + | 'status' + | 'last_status_reason' + | 'accepted_at' + | 'received_at' + | 'cancelled_at' + | 'on_chain_id' + | 'on_chain_block_num' + | 'on_chain_present' + | 'membership_fee' + > = { + status: entity.status, + last_status_reason: entity.last_status_reason, + accepted_at: entity.accepted_at, + received_at: entity.received_at, + cancelled_at: entity.cancelled_at, + on_chain_id: entity.on_chain_id, + on_chain_block_num: entity.on_chain_block_num, + on_chain_present: entity.on_chain_present, + membership_fee: entity.membership_fee, + }; + await this.repo.update({ id: entity.id }, patch); const row = await this.repo.findOneOrFail({ where: { id: entity.id } }); return this.mapper.toDomain(row); } diff --git a/components/controller/src/extensions/marketplace/infrastructure/entities/marketplace-order.entity.ts b/components/controller/src/extensions/marketplace/infrastructure/entities/marketplace-order.entity.ts index c6136ee3aac..06bec83514e 100644 --- a/components/controller/src/extensions/marketplace/infrastructure/entities/marketplace-order.entity.ts +++ b/components/controller/src/extensions/marketplace/infrastructure/entities/marketplace-order.entity.ts @@ -183,6 +183,15 @@ export class MarketplaceOrderEntity { @Column({ type: 'boolean', default: false }) public on_chain_present!: boolean; + /** + * Членский взнос, включённый в стоимость заказа (requirement b6). Контракт + * сам считает и пишет его в `order` row при `createorder` — это on-chain + * mirror, не backend-вычисление (см. domain MarketplaceOrderBlockchainData). + * Null до первой sync-дельты и у заказов, созданных до появления поля. + */ + @Column({ type: 'numeric', precision: 24, scale: 4, nullable: true }) + public membership_fee!: string | null; + @CreateDateColumn({ type: 'timestamptz' }) public created_at!: Date; diff --git a/components/controller/src/extensions/marketplace/infrastructure/mappers/marketplace-order-delta.mapper.ts b/components/controller/src/extensions/marketplace/infrastructure/mappers/marketplace-order-delta.mapper.ts index 0f7232fed85..e46aa422fcd 100644 --- a/components/controller/src/extensions/marketplace/infrastructure/mappers/marketplace-order-delta.mapper.ts +++ b/components/controller/src/extensions/marketplace/infrastructure/mappers/marketplace-order-delta.mapper.ts @@ -33,6 +33,10 @@ import { * содержит — их выставляет только backend (cycle-hook / app-слой), и они * никогда не приходят дельтой. Поэтому STATUS_MAP содержит ровно on-chain * значения; `cancelled` обрабатывается отдельно (см. KNOWN_UNMAPPED_STATUSES). + * + * requirement b6: `membership_fee` контракт считает и пишет в `order` row + * САМ (createorder.cpp, по ставке `mkt_config_singleton` на момент создания + * заказа) — backend его не вычисляет, только зеркалит через эту дельту. */ @Injectable() export class MarketplaceOrderDeltaMapper extends AbstractBlockchainDeltaMapper< @@ -91,6 +95,7 @@ export class MarketplaceOrderDeltaMapper extends AbstractBlockchainDeltaMapper< order_hash: value.hash, on_chain_id: value.id.toString(), status, + membership_fee: MarketplaceOrderDeltaMapper.parseAssetAmount(value.membership_fee), }; } catch (error: any) { this.logger.error( @@ -122,4 +127,16 @@ export class MarketplaceOrderDeltaMapper extends AbstractBlockchainDeltaMapper< getSupportedTableNames(): string[] { return ['orders']; } + + /** + * `membership_fee` on-chain — `binary_extension` вида `"45.0000 RUB"` + * (может отсутствовать у строк, созданных до requirement b6). Храним в БД + * как чистую numeric-строку без символа — тот же формат, что у + * `total_cost`/`price_per_unit` (см. `computeTotalCostAmount`). + */ + private static parseAssetAmount(asset: string | undefined): string | null { + if (!asset) return null; + const amount = asset.split(' ')[0]; + return Number.isNaN(Number(amount)) ? null : amount; + } } diff --git a/components/controller/src/extensions/marketplace/infrastructure/mappers/marketplace-order.mapper.ts b/components/controller/src/extensions/marketplace/infrastructure/mappers/marketplace-order.mapper.ts index cc3f9bac447..a1985f42c27 100644 --- a/components/controller/src/extensions/marketplace/infrastructure/mappers/marketplace-order.mapper.ts +++ b/components/controller/src/extensions/marketplace/infrastructure/mappers/marketplace-order.mapper.ts @@ -22,6 +22,7 @@ export class MarketplaceOrderMapper { quantity: row.quantity, price_per_unit: row.price_per_unit, total_cost: row.total_cost, + membership_fee: row.membership_fee ?? null, cycle_id: row.cycle_id, checkout_id: row.checkout_id ?? null, shipment_id: row.shipment_id ?? null, diff --git a/components/controller/zeus/const.ts b/components/controller/zeus/const.ts index ac2d0817a73..3c167a3a81f 100644 --- a/components/controller/zeus/const.ts +++ b/components/controller/zeus/const.ts @@ -4847,13 +4847,13 @@ export const ReturnTypes: Record = { coopname:"String", created_at:"DateTime", created_by_operator_account:"String", - cycle_id:"ID", + cycle_id:"String", expeditor_data:"MarketplaceShipmentTTNData", fact_quantity_per_order:"MarketplaceAplReceptionFactEntry", - id:"ID", + id:"String", offerer_account:"String", offerer_name:"String", - shipment_id:"ID", + shipment_id:"String", status:"MarketplaceAplReceptionStatus", supplier_signed_at:"DateTime", supplier_signsupp_tx_hash:"String", @@ -4865,7 +4865,7 @@ export const ReturnTypes: Record = { MarketplaceAplReceptionFactEntry:{ fact_quantity:"Int", fact_unit_price:"String", - order_id:"ID", + order_id:"String", product_name:"String", unit_of_measure:"String" }, @@ -5116,21 +5116,21 @@ export const ReturnTypes: Record = { delivery_point_address:"String", delivery_point_name:"String", expiry_date:"DateTime", - id:"ID", + id:"String", labeled_at:"DateTime", labeled_by_operator_account:"String", - order_id:"ID", + order_id:"String", orderer_account_snapshot:"String", orderer_name:"String", ownership:"MarketplaceInventoryOwnership", product_name_snapshot:"String", - published_offer_id:"ID", + published_offer_id:"String", quantity_per_label:"Int", received_at:"DateTime", received_by_operator_account:"String", - reserved_order_id:"ID", + reserved_order_id:"String", shelf:"String", - shipment_id:"ID", + shipment_id:"String", status:"MarketplaceInventoryStatus", unit_of_measure:"String", updated_at:"DateTime" @@ -5263,6 +5263,7 @@ export const ReturnTypes: Record = { id:"String", issuance_fact:"MarketplaceOrderIssuanceFactSnapshot", last_status_reason:"String", + membership_fee:"String", offer_hash:"String", offer_id:"String", order_hash:"String", @@ -5280,6 +5281,7 @@ export const ReturnTypes: Record = { supplier_account:"String", supplier_name:"String", total_cost:"String", + total_cost_with_fee:"String", unit_of_measure:"String", updated_at:"DateTime", warehouse_quantity:"Int", @@ -5317,15 +5319,15 @@ export const ReturnTypes: Record = { }, MarketplaceOutgoingPaymentRequest:{ amount:"String", - apl_reception_id:"ID", + apl_reception_id:"String", completed_at:"DateTime", coopname:"String", - core_payment_id:"ID", + core_payment_id:"String", created_at:"DateTime", decline_reason:"String", - id:"ID", + id:"String", order_hash:"String", - order_id:"ID", + order_id:"String", payee_account:"String", payout_destination:"String", payout_tx_hash:"String", @@ -5507,9 +5509,9 @@ export const ReturnTypes: Record = { braname:"String", coopname:"String", created_at:"DateTime", - cycle_id:"ID", + cycle_id:"String", delivery_variant:"MarketplaceShipmentDeliveryVariant", - id:"ID", + id:"String", offerer_account:"String", status:"MarketplaceShipmentStatus", total_amount:"String", @@ -5519,7 +5521,7 @@ export const ReturnTypes: Record = { updated_at:"DateTime" }, MarketplaceShipmentLinePackaging:{ - order_id:"ID", + order_id:"String", units_per_box:"Int" }, MarketplaceShipmentTTNData:{ @@ -5544,7 +5546,7 @@ export const ReturnTypes: Record = { order_lines:"MarketplaceStockAcceptOrderLine" }, MarketplaceStockIssuanceOperatorLine:{ - offer_id:"ID", + offer_id:"String", order_hash:"String", product_name:"String", quantity:"Int", @@ -5554,8 +5556,8 @@ export const ReturnTypes: Record = { MarketplaceStockProposal:{ braname:"String", created_at:"DateTime", - created_order_ids:"ID", - id:"ID", + created_order_ids:"String", + id:"String", items:"MarketplaceStockProposalItem", member_account:"String", operator_account:"String", @@ -5564,7 +5566,7 @@ export const ReturnTypes: Record = { total_cost:"String" }, MarketplaceStockProposalAcceptResult:{ - order_ids:"ID", + order_ids:"String", proposal:"MarketplaceStockProposal" }, MarketplaceStockProposalCreatedEvent:{ @@ -5572,7 +5574,7 @@ export const ReturnTypes: Record = { proposal_id:"String" }, MarketplaceStockProposalItem:{ - offer_id:"ID", + offer_id:"String", product_name:"String", quantity:"Int", unit_price:"String" diff --git a/components/controller/zeus/index.ts b/components/controller/zeus/index.ts index 0d91baec1ae..5f985cd6564 100644 --- a/components/controller/zeus/index.ts +++ b/components/controller/zeus/index.ts @@ -7715,7 +7715,7 @@ export type ValueTypes = { }>; ["MarketplaceAplReceptionByIdInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ValueTypes["ID"] | Variable + apl_reception_id: string | Variable }; ["MarketplaceAplReceptionFactEntry"]: AliasType<{ /** Фактически принятое количество (для расхождений Варианта Б). */ @@ -7734,7 +7734,7 @@ export type ValueTypes = { fact_quantity: number | Variable, /** Фактическая цена за единицу (оператор может изменить её при открытии приёмки). */ fact_unit_price?: string | undefined | null | Variable, - order_id: ValueTypes["ID"] | Variable + order_id: string | Variable }; ["MarketplaceAplReceptionResult"]: AliasType<{ apl_reception?:ValueTypes["MarketplaceAplReception"], @@ -7843,7 +7843,7 @@ export type ValueTypes = { }; ["MarketplaceAssignInventoryShelfInput"]: { /** Позиция склада, для которой назначается полка. */ - inventory_id: ValueTypes["ID"] | Variable, + inventory_id: string | Variable, /** Полка/ячейка склада (свободная строка). Пусто — очистить полку. */ shelf?: string | undefined | null | Variable }; @@ -7973,7 +7973,7 @@ export type ValueTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ValueTypes["MarketplaceBarcodeFormat"] | undefined | null | Variable, /** Позиция склада, к которой привязывается отсканированный штрих-код. */ - inventory_id: ValueTypes["ID"] | Variable + inventory_id: string | Variable }; /** Экономика кооперативного участка: общий кошелёк членских взносов, плановые расходы с резервом на 30 дней, веса участников распределения и балансы персональных кошельков. */ ["MarketplaceBranchEconomy"]: AliasType<{ @@ -8008,7 +8008,7 @@ export type ValueTypes = { }>; ["MarketplaceCancelStockOrderInput"]: { /** Заказ со склада кооператива, отменяемый до открытия выдачи. */ - order_id: ValueTypes["ID"] | Variable, + order_id: string | Variable, /** Причина отмены (видна пайщику в истории заказа). */ reason?: string | undefined | null | Variable }; @@ -8181,7 +8181,7 @@ export type ValueTypes = { }; ["MarketplaceClearInventoryLabelInput"]: { /** Позиция склада, с которой снимается штрих-код (для переклейки). */ - inventory_id: ValueTypes["ID"] | Variable + inventory_id: string | Variable }; ["MarketplaceConfirmWriteoffInput"]: { /** Кооперативный участок, по которому подтверждается списание. */ @@ -8298,7 +8298,7 @@ export type ValueTypes = { /** Опционально для Варианта Б — фактически принятое количество per-Order. Для пропущенных Order'ов берётся order.quantity. */ fact_quantity_per_order?: Array | undefined | null | Variable, /** Партия поставки в статусе SUPPLY_PREPARED. */ - shipment_id: ValueTypes["ID"] | Variable + shipment_id: string | Variable }; ["MarketplaceCreateExpressReceptionInput"]: { /** КУ, на котором оператор принимает имущество. */ @@ -8340,7 +8340,7 @@ export type ValueTypes = { /** Фактическая цена за единицу (оператор мог скорректировать). */ actual_unit_price: string | Variable, /** Существующий заказ пайщика к выдаче этим бандлом. */ - order_id: ValueTypes["ID"] | Variable, + order_id: string | Variable, /** Акт приёма-передачи, подписанный оператором КУ первой подписью. */ signiss1_act: ValueTypes["MarketplaceIssueActSignedDocumentInput"] | Variable }; @@ -8360,7 +8360,7 @@ export type ValueTypes = { }; ["MarketplaceCreateShipmentInput"]: { /** Идентификатор консолидированной заявки в статусе ACCEPTED. */ - cycle_id: ValueTypes["ID"] | Variable, + cycle_id: string | Variable, /** Группы доставки по КУ заявки. Каждая группа = одна партия (один КУ, один вариант доставки, опционально подмножество заказов). Покрытие всех КУ заявки не требуется — можно формировать частично и догружать остаток отдельными партиями. */ groups: Array | Variable }; @@ -8382,7 +8382,7 @@ export type ValueTypes = { }; ["MarketplaceCreateStockProposalLineInput"]: { /** Предложение кооператива из остатка. */ - offer_id: ValueTypes["ID"] | Variable, + offer_id: string | Variable, /** order_hash из подготовки (marketplaceStockIssuancePayloads). */ order_hash: string | Variable, /** Количество единиц. */ @@ -8512,7 +8512,7 @@ export type ValueTypes = { /** Строки докладки с подписью получения (signiss2) из marketplaceStockProposalSignablePayloads. */ order_lines: Array | Variable, /** Предложение со склада кооператива. */ - proposal_id: ValueTypes["ID"] | Variable, + proposal_id: string | Variable, /** Единое подписанное Заявление о конвертации на всю сумму доплаты с паевого. Не передаётся, когда членских средств хватает. */ signed_convert?: ValueTypes["MarketplaceConvertStatementSignedInput"] | undefined | null | Variable }; @@ -8520,7 +8520,7 @@ export type ValueTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ValueTypes["MarketplaceBarcodeFormat"] | undefined | null | Variable, /** Позиция склада, на которую наклеивается штрих-код. */ - inventory_id: ValueTypes["ID"] | Variable + inventory_id: string | Variable }; /** Состояние геокодинга адреса: PENDING — в процессе, OK — успешно, FAILED — ошибка. */ ["MarketplaceGeocodeStatus"]:MarketplaceGeocodeStatus; @@ -8531,7 +8531,7 @@ export type ValueTypes = { }; ["MarketplaceGetShipmentInput"]: { /** Идентификатор партии поставки. */ - shipment_id: ValueTypes["ID"] | Variable + shipment_id: string | Variable }; ["MarketplaceInventoryItem"]: AliasType<{ /** Цена прибытия за единицу (закупочная из акта приёмки) — база цены публикации остатка. */ @@ -8758,9 +8758,9 @@ export type ValueTypes = { /** Фильтр по КУ. */ braname?: string | undefined | null | Variable, /** Фильтр по заказу. */ - order_id?: ValueTypes["ID"] | undefined | null | Variable, + order_id?: string | undefined | null | Variable, /** Фильтр по партии поставки. */ - shipment_id?: ValueTypes["ID"] | undefined | null | Variable, + shipment_id?: string | undefined | null | Variable, /** Фильтр по состояниям склада. */ statuses?: Array | undefined | null | Variable }; @@ -8823,7 +8823,7 @@ export type ValueTypes = { /** Фильтр по КУ-получателю. */ braname?: string | undefined | null | Variable, /** Фильтр по консолидированной заявке. */ - cycle_id?: ValueTypes["ID"] | undefined | null | Variable, + cycle_id?: string | undefined | null | Variable, /** Фильтр по статусам партий. */ statuses?: Array | undefined | null | Variable }; @@ -9045,6 +9045,8 @@ export type ValueTypes = { issuance_fact?:ValueTypes["MarketplaceOrderIssuanceFactSnapshot"], /** Текстовая причина последнего изменения статуса. */ last_status_reason?:boolean | `@${string}`, + /** Членский взнос, включённый в стоимость заказа, по ставке на момент оформления. Заказчик платит total_cost + membership_fee; пусто — заказ ещё не подтверждён блокчейном. */ + membership_fee?:boolean | `@${string}`, /** Хеш предложения в блокчейне (snapshot на момент заказа). */ offer_hash?:boolean | `@${string}`, /** Идентификатор предложения, по которому оформлен заказ. */ @@ -9077,8 +9079,10 @@ export type ValueTypes = { supplier_account?:boolean | `@${string}`, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ supplier_name?:boolean | `@${string}`, - /** Общая сумма заказа. */ + /** Общая сумма заказа (стоимость имущества без членского взноса). */ total_cost?:boolean | `@${string}`, + /** Полная сумма к оплате заказчиком: total_cost + membership_fee. Готовое значение — клиенту не нужно складывать поля самому. */ + total_cost_with_fee?:boolean | `@${string}`, /** Единица измерения товара из предложения (шт., кг, л, упак.). */ unit_of_measure?:boolean | `@${string}`, /** Когда запись о заказе последний раз изменялась. */ @@ -9227,7 +9231,7 @@ export type ValueTypes = { }>; ["MarketplacePublishStockInput"]: { /** Позиции свободного остатка склада для публикации в каталог. */ - inventory_ids: Array | Variable, + inventory_ids: Array | Variable, /** Цена за единицу при публикации. Пусто — цена прибытия; меньше цены прибытия — уценка. */ price_per_unit?: string | undefined | null | Variable }; @@ -9457,7 +9461,7 @@ export type ValueTypes = { }; ["MarketplaceResolveStockProposalInput"]: { /** Предложение со склада кооператива. */ - proposal_id: ValueTypes["ID"] | Variable + proposal_id: string | Variable }; /** Заявление пайщика на гарантийный возврат имущества (Эпик 7). */ ["MarketplaceReturnClaim"]: AliasType<{ @@ -9716,7 +9720,7 @@ export type ValueTypes = { braname: string | Variable, delivery_variant: ValueTypes["MarketplaceShipmentDeliveryVariant"] | Variable, /** Подмножество заказов этого КУ, реально погружаемых в партию (частичная отгрузка). Пусто → все акцептованные заказы КУ (поведение по умолчанию). Невключённые заказы остаются ACCEPTED и доступны для следующей партии. */ - order_ids?: Array | undefined | null | Variable, + order_ids?: Array | undefined | null | Variable, /** Поля ТТН — обязательны для Варианта Б. */ ttn_data?: ValueTypes["MarketplaceShipmentTTNDataInput"] | undefined | null | Variable }; @@ -9730,7 +9734,7 @@ export type ValueTypes = { }>; ["MarketplaceShipmentLinePackagingInput"]: { /** Заказ партии, к которому относится упаковка. */ - order_id: ValueTypes["ID"] | Variable, + order_id: string | Variable, /** Сколько единиц имущества в одной коробке. */ units_per_box: number | Variable }; @@ -9766,7 +9770,7 @@ export type ValueTypes = { }; ["MarketplaceSignAplReceptionInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ValueTypes["ID"] | Variable, + apl_reception_id: string | Variable, /** Подписанные клиентом акты приёмки — один документ на каждый Order группы. Backend верифицирует подпись и отправляет on-chain signsupp/signchair с этим документом. */ signed_documents: Array | Variable }; @@ -9776,7 +9780,7 @@ export type ValueTypes = { }; ["MarketplaceSplitInventoryInput"]: { /** Позиция склада, которую раскладывают по нескольким полкам. */ - inventory_id: ValueTypes["ID"] | Variable, + inventory_id: string | Variable, /** Доли разбиения; сумма количеств обязана равняться количеству позиции. */ splits: Array | Variable }; @@ -9885,7 +9889,7 @@ export type ValueTypes = { }>; ["MarketplaceStockProposalItemInput"]: { /** Предложение кооператива из опубликованного остатка. */ - offer_id: ValueTypes["ID"] | Variable, + offer_id: string | Variable, /** Количество единиц, предлагаемое пайщику. */ quantity: number | Variable }; @@ -9985,7 +9989,7 @@ export type ValueTypes = { }>; ["MarketplaceUnpublishStockInput"]: { /** Опубликованные позиции остатка, снимаемые с витрины. */ - inventory_ids: Array | Variable + inventory_ids: Array | Variable }; ["MarketplaceUnpublishStockResult"]: AliasType<{ /** Сколько позиций снято с публикации. */ @@ -20738,7 +20742,7 @@ export type ResolverInputTypes = { }>; ["MarketplaceAplReceptionByIdInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ResolverInputTypes["ID"] + apl_reception_id: string }; ["MarketplaceAplReceptionFactEntry"]: AliasType<{ /** Фактически принятое количество (для расхождений Варианта Б). */ @@ -20756,7 +20760,7 @@ export type ResolverInputTypes = { fact_quantity: number, /** Фактическая цена за единицу (оператор может изменить её при открытии приёмки). */ fact_unit_price?: string | undefined | null, - order_id: ResolverInputTypes["ID"] + order_id: string }; ["MarketplaceAplReceptionResult"]: AliasType<{ apl_reception?:ResolverInputTypes["MarketplaceAplReception"], @@ -20863,7 +20867,7 @@ export type ResolverInputTypes = { }; ["MarketplaceAssignInventoryShelfInput"]: { /** Позиция склада, для которой назначается полка. */ - inventory_id: ResolverInputTypes["ID"], + inventory_id: string, /** Полка/ячейка склада (свободная строка). Пусто — очистить полку. */ shelf?: string | undefined | null }; @@ -20987,7 +20991,7 @@ export type ResolverInputTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ResolverInputTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, к которой привязывается отсканированный штрих-код. */ - inventory_id: ResolverInputTypes["ID"] + inventory_id: string }; /** Экономика кооперативного участка: общий кошелёк членских взносов, плановые расходы с резервом на 30 дней, веса участников распределения и балансы персональных кошельков. */ ["MarketplaceBranchEconomy"]: AliasType<{ @@ -21020,7 +21024,7 @@ export type ResolverInputTypes = { }>; ["MarketplaceCancelStockOrderInput"]: { /** Заказ со склада кооператива, отменяемый до открытия выдачи. */ - order_id: ResolverInputTypes["ID"], + order_id: string, /** Причина отмены (видна пайщику в истории заказа). */ reason?: string | undefined | null }; @@ -21183,7 +21187,7 @@ export type ResolverInputTypes = { }; ["MarketplaceClearInventoryLabelInput"]: { /** Позиция склада, с которой снимается штрих-код (для переклейки). */ - inventory_id: ResolverInputTypes["ID"] + inventory_id: string }; ["MarketplaceConfirmWriteoffInput"]: { /** Кооперативный участок, по которому подтверждается списание. */ @@ -21297,7 +21301,7 @@ export type ResolverInputTypes = { /** Опционально для Варианта Б — фактически принятое количество per-Order. Для пропущенных Order'ов берётся order.quantity. */ fact_quantity_per_order?: Array | undefined | null, /** Партия поставки в статусе SUPPLY_PREPARED. */ - shipment_id: ResolverInputTypes["ID"] + shipment_id: string }; ["MarketplaceCreateExpressReceptionInput"]: { /** КУ, на котором оператор принимает имущество. */ @@ -21338,7 +21342,7 @@ export type ResolverInputTypes = { /** Фактическая цена за единицу (оператор мог скорректировать). */ actual_unit_price: string, /** Существующий заказ пайщика к выдаче этим бандлом. */ - order_id: ResolverInputTypes["ID"], + order_id: string, /** Акт приёма-передачи, подписанный оператором КУ первой подписью. */ signiss1_act: ResolverInputTypes["MarketplaceIssueActSignedDocumentInput"] }; @@ -21358,7 +21362,7 @@ export type ResolverInputTypes = { }; ["MarketplaceCreateShipmentInput"]: { /** Идентификатор консолидированной заявки в статусе ACCEPTED. */ - cycle_id: ResolverInputTypes["ID"], + cycle_id: string, /** Группы доставки по КУ заявки. Каждая группа = одна партия (один КУ, один вариант доставки, опционально подмножество заказов). Покрытие всех КУ заявки не требуется — можно формировать частично и догружать остаток отдельными партиями. */ groups: Array }; @@ -21379,7 +21383,7 @@ export type ResolverInputTypes = { }; ["MarketplaceCreateStockProposalLineInput"]: { /** Предложение кооператива из остатка. */ - offer_id: ResolverInputTypes["ID"], + offer_id: string, /** order_hash из подготовки (marketplaceStockIssuancePayloads). */ order_hash: string, /** Количество единиц. */ @@ -21505,7 +21509,7 @@ export type ResolverInputTypes = { /** Строки докладки с подписью получения (signiss2) из marketplaceStockProposalSignablePayloads. */ order_lines: Array, /** Предложение со склада кооператива. */ - proposal_id: ResolverInputTypes["ID"], + proposal_id: string, /** Единое подписанное Заявление о конвертации на всю сумму доплаты с паевого. Не передаётся, когда членских средств хватает. */ signed_convert?: ResolverInputTypes["MarketplaceConvertStatementSignedInput"] | undefined | null }; @@ -21513,7 +21517,7 @@ export type ResolverInputTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ResolverInputTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, на которую наклеивается штрих-код. */ - inventory_id: ResolverInputTypes["ID"] + inventory_id: string }; /** Состояние геокодинга адреса: PENDING — в процессе, OK — успешно, FAILED — ошибка. */ ["MarketplaceGeocodeStatus"]:MarketplaceGeocodeStatus; @@ -21524,7 +21528,7 @@ export type ResolverInputTypes = { }; ["MarketplaceGetShipmentInput"]: { /** Идентификатор партии поставки. */ - shipment_id: ResolverInputTypes["ID"] + shipment_id: string }; ["MarketplaceInventoryItem"]: AliasType<{ /** Цена прибытия за единицу (закупочная из акта приёмки) — база цены публикации остатка. */ @@ -21748,9 +21752,9 @@ export type ResolverInputTypes = { /** Фильтр по КУ. */ braname?: string | undefined | null, /** Фильтр по заказу. */ - order_id?: ResolverInputTypes["ID"] | undefined | null, + order_id?: string | undefined | null, /** Фильтр по партии поставки. */ - shipment_id?: ResolverInputTypes["ID"] | undefined | null, + shipment_id?: string | undefined | null, /** Фильтр по состояниям склада. */ statuses?: Array | undefined | null }; @@ -21813,7 +21817,7 @@ export type ResolverInputTypes = { /** Фильтр по КУ-получателю. */ braname?: string | undefined | null, /** Фильтр по консолидированной заявке. */ - cycle_id?: ResolverInputTypes["ID"] | undefined | null, + cycle_id?: string | undefined | null, /** Фильтр по статусам партий. */ statuses?: Array | undefined | null }; @@ -22025,6 +22029,8 @@ export type ResolverInputTypes = { issuance_fact?:ResolverInputTypes["MarketplaceOrderIssuanceFactSnapshot"], /** Текстовая причина последнего изменения статуса. */ last_status_reason?:boolean | `@${string}`, + /** Членский взнос, включённый в стоимость заказа, по ставке на момент оформления. Заказчик платит total_cost + membership_fee; пусто — заказ ещё не подтверждён блокчейном. */ + membership_fee?:boolean | `@${string}`, /** Хеш предложения в блокчейне (snapshot на момент заказа). */ offer_hash?:boolean | `@${string}`, /** Идентификатор предложения, по которому оформлен заказ. */ @@ -22057,8 +22063,10 @@ export type ResolverInputTypes = { supplier_account?:boolean | `@${string}`, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ supplier_name?:boolean | `@${string}`, - /** Общая сумма заказа. */ + /** Общая сумма заказа (стоимость имущества без членского взноса). */ total_cost?:boolean | `@${string}`, + /** Полная сумма к оплате заказчиком: total_cost + membership_fee. Готовое значение — клиенту не нужно складывать поля самому. */ + total_cost_with_fee?:boolean | `@${string}`, /** Единица измерения товара из предложения (шт., кг, л, упак.). */ unit_of_measure?:boolean | `@${string}`, /** Когда запись о заказе последний раз изменялась. */ @@ -22197,7 +22205,7 @@ export type ResolverInputTypes = { }>; ["MarketplacePublishStockInput"]: { /** Позиции свободного остатка склада для публикации в каталог. */ - inventory_ids: Array, + inventory_ids: Array, /** Цена за единицу при публикации. Пусто — цена прибытия; меньше цены прибытия — уценка. */ price_per_unit?: string | undefined | null }; @@ -22421,7 +22429,7 @@ export type ResolverInputTypes = { }; ["MarketplaceResolveStockProposalInput"]: { /** Предложение со склада кооператива. */ - proposal_id: ResolverInputTypes["ID"] + proposal_id: string }; /** Заявление пайщика на гарантийный возврат имущества (Эпик 7). */ ["MarketplaceReturnClaim"]: AliasType<{ @@ -22672,7 +22680,7 @@ export type ResolverInputTypes = { braname: string, delivery_variant: ResolverInputTypes["MarketplaceShipmentDeliveryVariant"], /** Подмножество заказов этого КУ, реально погружаемых в партию (частичная отгрузка). Пусто → все акцептованные заказы КУ (поведение по умолчанию). Невключённые заказы остаются ACCEPTED и доступны для следующей партии. */ - order_ids?: Array | undefined | null, + order_ids?: Array | undefined | null, /** Поля ТТН — обязательны для Варианта Б. */ ttn_data?: ResolverInputTypes["MarketplaceShipmentTTNDataInput"] | undefined | null }; @@ -22685,7 +22693,7 @@ export type ResolverInputTypes = { }>; ["MarketplaceShipmentLinePackagingInput"]: { /** Заказ партии, к которому относится упаковка. */ - order_id: ResolverInputTypes["ID"], + order_id: string, /** Сколько единиц имущества в одной коробке. */ units_per_box: number }; @@ -22720,7 +22728,7 @@ export type ResolverInputTypes = { }; ["MarketplaceSignAplReceptionInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ResolverInputTypes["ID"], + apl_reception_id: string, /** Подписанные клиентом акты приёмки — один документ на каждый Order группы. Backend верифицирует подпись и отправляет on-chain signsupp/signchair с этим документом. */ signed_documents: Array }; @@ -22730,7 +22738,7 @@ export type ResolverInputTypes = { }; ["MarketplaceSplitInventoryInput"]: { /** Позиция склада, которую раскладывают по нескольким полкам. */ - inventory_id: ResolverInputTypes["ID"], + inventory_id: string, /** Доли разбиения; сумма количеств обязана равняться количеству позиции. */ splits: Array }; @@ -22832,7 +22840,7 @@ export type ResolverInputTypes = { }>; ["MarketplaceStockProposalItemInput"]: { /** Предложение кооператива из опубликованного остатка. */ - offer_id: ResolverInputTypes["ID"], + offer_id: string, /** Количество единиц, предлагаемое пайщику. */ quantity: number }; @@ -22927,7 +22935,7 @@ export type ResolverInputTypes = { }>; ["MarketplaceUnpublishStockInput"]: { /** Опубликованные позиции остатка, снимаемые с витрины. */ - inventory_ids: Array + inventory_ids: Array }; ["MarketplaceUnpublishStockResult"]: AliasType<{ /** Сколько позиций снято с публикации. */ @@ -33347,18 +33355,18 @@ export type ModelTypes = { created_at: ModelTypes["DateTime"], created_by_operator_account: string, /** Консолидированная заявка. */ - cycle_id: ModelTypes["ID"], + cycle_id: string, /** Снапшот данных экспедитора + ТТН (только для Варианта Б). */ expeditor_data?: ModelTypes["MarketplaceShipmentTTNData"] | undefined | null, /** Фактически принятое количество per-Order. */ fact_quantity_per_order: Array, - id: ModelTypes["ID"], + id: string, /** Account поставщика-владельца Offer'ов. */ offerer_account: string, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ offerer_name?: string | undefined | null, /** Партия поставки, по которой формируется приёмка. */ - shipment_id: ModelTypes["ID"], + shipment_id: string, status: ModelTypes["MarketplaceAplReceptionStatus"], supplier_signed_at?: ModelTypes["DateTime"] | undefined | null, /** Хэш транзакции подписи поставщика. */ @@ -33372,14 +33380,14 @@ export type ModelTypes = { }; ["MarketplaceAplReceptionByIdInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ModelTypes["ID"] + apl_reception_id: string }; ["MarketplaceAplReceptionFactEntry"]: { /** Фактически принятое количество (для расхождений Варианта Б). */ fact_quantity: number, /** Фактическая цена за единицу (если оператор скорректировал её при открытии приёмки). */ fact_unit_price?: string | undefined | null, - order_id: ModelTypes["ID"], + order_id: string, /** Наименование товара по этой позиции — для таблицы сверки в диалоге подписи. */ product_name?: string | undefined | null, /** Единица измерения товара по этой позиции (шт., кг, л, упак.). */ @@ -33389,7 +33397,7 @@ export type ModelTypes = { fact_quantity: number, /** Фактическая цена за единицу (оператор может изменить её при открытии приёмки). */ fact_unit_price?: string | undefined | null, - order_id: ModelTypes["ID"] + order_id: string }; ["MarketplaceAplReceptionResult"]: { apl_reception: ModelTypes["MarketplaceAplReception"] @@ -33492,7 +33500,7 @@ export type ModelTypes = { }; ["MarketplaceAssignInventoryShelfInput"]: { /** Позиция склада, для которой назначается полка. */ - inventory_id: ModelTypes["ID"], + inventory_id: string, /** Полка/ячейка склада (свободная строка). Пусто — очистить полку. */ shelf?: string | undefined | null }; @@ -33607,7 +33615,7 @@ export type ModelTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ModelTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, к которой привязывается отсканированный штрих-код. */ - inventory_id: ModelTypes["ID"] + inventory_id: string }; /** Экономика кооперативного участка: общий кошелёк членских взносов, плановые расходы с резервом на 30 дней, веса участников распределения и балансы персональных кошельков. */ ["MarketplaceBranchEconomy"]: { @@ -33638,7 +33646,7 @@ export type ModelTypes = { }; ["MarketplaceCancelStockOrderInput"]: { /** Заказ со склада кооператива, отменяемый до открытия выдачи. */ - order_id: ModelTypes["ID"], + order_id: string, /** Причина отмены (видна пайщику в истории заказа). */ reason?: string | undefined | null }; @@ -33791,7 +33799,7 @@ export type ModelTypes = { }; ["MarketplaceClearInventoryLabelInput"]: { /** Позиция склада, с которой снимается штрих-код (для переклейки). */ - inventory_id: ModelTypes["ID"] + inventory_id: string }; ["MarketplaceConfirmWriteoffInput"]: { /** Кооперативный участок, по которому подтверждается списание. */ @@ -33901,7 +33909,7 @@ export type ModelTypes = { /** Опционально для Варианта Б — фактически принятое количество per-Order. Для пропущенных Order'ов берётся order.quantity. */ fact_quantity_per_order?: Array | undefined | null, /** Партия поставки в статусе SUPPLY_PREPARED. */ - shipment_id: ModelTypes["ID"] + shipment_id: string }; ["MarketplaceCreateExpressReceptionInput"]: { /** КУ, на котором оператор принимает имущество. */ @@ -33941,7 +33949,7 @@ export type ModelTypes = { /** Фактическая цена за единицу (оператор мог скорректировать). */ actual_unit_price: string, /** Существующий заказ пайщика к выдаче этим бандлом. */ - order_id: ModelTypes["ID"], + order_id: string, /** Акт приёма-передачи, подписанный оператором КУ первой подписью. */ signiss1_act: ModelTypes["MarketplaceIssueActSignedDocumentInput"] }; @@ -33961,7 +33969,7 @@ export type ModelTypes = { }; ["MarketplaceCreateShipmentInput"]: { /** Идентификатор консолидированной заявки в статусе ACCEPTED. */ - cycle_id: ModelTypes["ID"], + cycle_id: string, /** Группы доставки по КУ заявки. Каждая группа = одна партия (один КУ, один вариант доставки, опционально подмножество заказов). Покрытие всех КУ заявки не требуется — можно формировать частично и догружать остаток отдельными партиями. */ groups: Array }; @@ -33981,7 +33989,7 @@ export type ModelTypes = { }; ["MarketplaceCreateStockProposalLineInput"]: { /** Предложение кооператива из остатка. */ - offer_id: ModelTypes["ID"], + offer_id: string, /** order_hash из подготовки (marketplaceStockIssuancePayloads). */ order_hash: string, /** Количество единиц. */ @@ -34088,7 +34096,7 @@ export type ModelTypes = { /** Строки докладки с подписью получения (signiss2) из marketplaceStockProposalSignablePayloads. */ order_lines: Array, /** Предложение со склада кооператива. */ - proposal_id: ModelTypes["ID"], + proposal_id: string, /** Единое подписанное Заявление о конвертации на всю сумму доплаты с паевого. Не передаётся, когда членских средств хватает. */ signed_convert?: ModelTypes["MarketplaceConvertStatementSignedInput"] | undefined | null }; @@ -34096,7 +34104,7 @@ export type ModelTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ModelTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, на которую наклеивается штрих-код. */ - inventory_id: ModelTypes["ID"] + inventory_id: string }; ["MarketplaceGeocodeStatus"]:MarketplaceGeocodeStatus; /** Параметры запроса одного заказа. */ @@ -34106,7 +34114,7 @@ export type ModelTypes = { }; ["MarketplaceGetShipmentInput"]: { /** Идентификатор партии поставки. */ - shipment_id: ModelTypes["ID"] + shipment_id: string }; ["MarketplaceInventoryItem"]: { /** Цена прибытия за единицу (закупочная из акта приёмки) — база цены публикации остатка. */ @@ -34125,13 +34133,13 @@ export type ModelTypes = { delivery_point_name?: string | undefined | null, /** Срок годности имущества. По нему идёт списание просрочки — ключевой параметр контроля склада. Пусто — срок не задан. */ expiry_date?: ModelTypes["DateTime"] | undefined | null, - id: ModelTypes["ID"], + id: string, /** Момент маркировки штрих-кодом (если есть). */ labeled_at?: ModelTypes["DateTime"] | undefined | null, /** Оператор КУ, наклеивший штрих-код (если позиция промаркирована). */ labeled_by_operator_account?: string | undefined | null, /** Заказ, к которому относится позиция. */ - order_id: ModelTypes["ID"], + order_id: string, /** Заказчик — печатается на наклейке. */ orderer_account_snapshot: string, /** Фамилия Имя Отчество заказчика (организация — краткое наименование). Для показа в списках вместо служебного имени аккаунта. */ @@ -34141,7 +34149,7 @@ export type ModelTypes = { /** Наименование товара — для печатной наклейки. */ product_name_snapshot: string, /** Предложение кооператива, которым остаток опубликован в каталоге. Пусто — не опубликован. */ - published_offer_id?: ModelTypes["ID"] | undefined | null, + published_offer_id?: string | undefined | null, /** Количество единиц имущества в этой позиции склада. */ quantity_per_label: number, /** Момент приёмки имущества кооперативом по акту. */ @@ -34149,11 +34157,11 @@ export type ModelTypes = { /** Оператор КУ, оформивший приёмку. */ received_by_operator_account: string, /** Заказ со склада кооператива, под который позиция зарезервирована. Пусто — свободна. */ - reserved_order_id?: ModelTypes["ID"] | undefined | null, + reserved_order_id?: string | undefined | null, /** Полка/ячейка склада, куда положена позиция. Пусто — место не назначено. */ shelf?: string | undefined | null, /** Партия поставки, в составе которой имущество получено. */ - shipment_id: ModelTypes["ID"], + shipment_id: string, status: ModelTypes["MarketplaceInventoryStatus"], /** Единица измерения товара (шт./кг/литр/упак.) — из предложения. Для подписей количества на складе. */ unit_of_measure?: string | undefined | null, @@ -34324,9 +34332,9 @@ export type ModelTypes = { /** Фильтр по КУ. */ braname?: string | undefined | null, /** Фильтр по заказу. */ - order_id?: ModelTypes["ID"] | undefined | null, + order_id?: string | undefined | null, /** Фильтр по партии поставки. */ - shipment_id?: ModelTypes["ID"] | undefined | null, + shipment_id?: string | undefined | null, /** Фильтр по состояниям склада. */ statuses?: Array | undefined | null }; @@ -34389,7 +34397,7 @@ export type ModelTypes = { /** Фильтр по КУ-получателю. */ braname?: string | undefined | null, /** Фильтр по консолидированной заявке. */ - cycle_id?: ModelTypes["ID"] | undefined | null, + cycle_id?: string | undefined | null, /** Фильтр по статусам партий. */ statuses?: Array | undefined | null }; @@ -34590,6 +34598,8 @@ export type ModelTypes = { issuance_fact?: ModelTypes["MarketplaceOrderIssuanceFactSnapshot"] | undefined | null, /** Текстовая причина последнего изменения статуса. */ last_status_reason?: string | undefined | null, + /** Членский взнос, включённый в стоимость заказа, по ставке на момент оформления. Заказчик платит total_cost + membership_fee; пусто — заказ ещё не подтверждён блокчейном. */ + membership_fee?: string | undefined | null, /** Хеш предложения в блокчейне (snapshot на момент заказа). */ offer_hash: string, /** Идентификатор предложения, по которому оформлен заказ. */ @@ -34622,8 +34632,10 @@ export type ModelTypes = { supplier_account: string, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ supplier_name?: string | undefined | null, - /** Общая сумма заказа. */ + /** Общая сумма заказа (стоимость имущества без членского взноса). */ total_cost: string, + /** Полная сумма к оплате заказчиком: total_cost + membership_fee. Готовое значение — клиенту не нужно складывать поля самому. */ + total_cost_with_fee: string, /** Единица измерения товара из предложения (шт., кг, л, упак.). */ unit_of_measure?: string | undefined | null, /** Когда запись о заказе последний раз изменялась. */ @@ -34694,19 +34706,19 @@ export type ModelTypes = { /** Сумма платежа (numeric с 4 знаками). */ amount: string, /** Акт приёмки, по которому возникло обязательство. */ - apl_reception_id: ModelTypes["ID"], + apl_reception_id: string, completed_at?: ModelTypes["DateTime"] | undefined | null, coopname: string, /** Идентификатор связанного платежа в общем реестре кооператива — кассир видит выплату в общей ленте платежей. */ - core_payment_id?: ModelTypes["ID"] | undefined | null, + core_payment_id?: string | undefined | null, created_at: ModelTypes["DateTime"], /** Причина отказа банковского перевода, если кассир отказал в проведении. */ decline_reason?: string | undefined | null, - id: ModelTypes["ID"], + id: string, /** Хэш заказа в каталоге поставок — один заказ = одна выплата. */ order_hash: string, /** Идентификатор заказа в каталоге поставок. */ - order_id: ModelTypes["ID"], + order_id: string, /** Аккаунт поставщика — получатель выплаты. */ payee_account: string, /** Куда уходит выплата — короткая подпись реквизитов, например «Сбербанк •1234». */ @@ -34749,7 +34761,7 @@ export type ModelTypes = { }; ["MarketplacePublishStockInput"]: { /** Позиции свободного остатка склада для публикации в каталог. */ - inventory_ids: Array, + inventory_ids: Array, /** Цена за единицу при публикации. Пусто — цена прибытия; меньше цены прибытия — уценка. */ price_per_unit?: string | undefined | null }; @@ -34967,7 +34979,7 @@ export type ModelTypes = { }; ["MarketplaceResolveStockProposalInput"]: { /** Предложение со склада кооператива. */ - proposal_id: ModelTypes["ID"] + proposal_id: string }; /** Заявление пайщика на гарантийный возврат имущества (Эпик 7). */ ["MarketplaceReturnClaim"]: { @@ -35183,10 +35195,10 @@ export type ModelTypes = { coopname: string, created_at: ModelTypes["DateTime"], /** Идентификатор консолидированной заявки. */ - cycle_id: ModelTypes["ID"], + cycle_id: string, /** Выбранный вариант доставки. */ delivery_variant: ModelTypes["MarketplaceShipmentDeliveryVariant"], - id: ModelTypes["ID"], + id: string, /** Account поставщика-владельца Offer'ов. */ offerer_account: string, status: ModelTypes["MarketplaceShipmentStatus"], @@ -35206,19 +35218,19 @@ export type ModelTypes = { braname: string, delivery_variant: ModelTypes["MarketplaceShipmentDeliveryVariant"], /** Подмножество заказов этого КУ, реально погружаемых в партию (частичная отгрузка). Пусто → все акцептованные заказы КУ (поведение по умолчанию). Невключённые заказы остаются ACCEPTED и доступны для следующей партии. */ - order_ids?: Array | undefined | null, + order_ids?: Array | undefined | null, /** Поля ТТН — обязательны для Варианта Б. */ ttn_data?: ModelTypes["MarketplaceShipmentTTNDataInput"] | undefined | null }; ["MarketplaceShipmentLinePackaging"]: { /** Заказ партии, к которому относится упаковка. */ - order_id: ModelTypes["ID"], + order_id: string, /** Сколько единиц имущества в одной коробке. */ units_per_box: number }; ["MarketplaceShipmentLinePackagingInput"]: { /** Заказ партии, к которому относится упаковка. */ - order_id: ModelTypes["ID"], + order_id: string, /** Сколько единиц имущества в одной коробке. */ units_per_box: number }; @@ -35251,7 +35263,7 @@ export type ModelTypes = { }; ["MarketplaceSignAplReceptionInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ModelTypes["ID"], + apl_reception_id: string, /** Подписанные клиентом акты приёмки — один документ на каждый Order группы. Backend верифицирует подпись и отправляет on-chain signsupp/signchair с этим документом. */ signed_documents: Array }; @@ -35261,7 +35273,7 @@ export type ModelTypes = { }; ["MarketplaceSplitInventoryInput"]: { /** Позиция склада, которую раскладывают по нескольким полкам. */ - inventory_id: ModelTypes["ID"], + inventory_id: string, /** Доли разбиения; сумма количеств обязана равняться количеству позиции. */ splits: Array }; @@ -35293,7 +35305,7 @@ export type ModelTypes = { }; ["MarketplaceStockIssuanceOperatorLine"]: { /** Предложение кооператива из остатка. */ - offer_id: ModelTypes["ID"], + offer_id: string, /** Детерминированный order_hash будущего заказа из остатка. */ order_hash: string, /** Наименование товара. */ @@ -35318,8 +35330,8 @@ export type ModelTypes = { braname: string, created_at: ModelTypes["DateTime"], /** Заказы, созданные при принятии предложения. */ - created_order_ids: Array, - id: ModelTypes["ID"], + created_order_ids: Array, + id: string, /** Строки предложения. */ items: Array, /** Пайщик-адресат предложения. */ @@ -35334,7 +35346,7 @@ export type ModelTypes = { }; ["MarketplaceStockProposalAcceptResult"]: { /** Созданные заказы со склада кооператива. */ - order_ids: Array, + order_ids: Array, proposal: ModelTypes["MarketplaceStockProposal"] }; /** Оператор пункта выдачи предложил пайщику имущество со склада кооператива — требуется решение пайщика. */ @@ -35346,7 +35358,7 @@ export type ModelTypes = { }; ["MarketplaceStockProposalItem"]: { /** Предложение кооператива из остатка. */ - offer_id: ModelTypes["ID"], + offer_id: string, /** Наименование товара. */ product_name: string, /** Предложенное количество единиц. */ @@ -35356,7 +35368,7 @@ export type ModelTypes = { }; ["MarketplaceStockProposalItemInput"]: { /** Предложение кооператива из опубликованного остатка. */ - offer_id: ModelTypes["ID"], + offer_id: string, /** Количество единиц, предлагаемое пайщику. */ quantity: number }; @@ -35443,7 +35455,7 @@ export type ModelTypes = { }; ["MarketplaceUnpublishStockInput"]: { /** Опубликованные позиции остатка, снимаемые с витрины. */ - inventory_ids: Array + inventory_ids: Array }; ["MarketplaceUnpublishStockResult"]: { /** Сколько позиций снято с публикации. */ @@ -47016,18 +47028,18 @@ export type GraphQLTypes = { created_at: GraphQLTypes["DateTime"], created_by_operator_account: string, /** Консолидированная заявка. */ - cycle_id: GraphQLTypes["ID"], + cycle_id: string, /** Снапшот данных экспедитора + ТТН (только для Варианта Б). */ expeditor_data?: GraphQLTypes["MarketplaceShipmentTTNData"] | undefined | null, /** Фактически принятое количество per-Order. */ fact_quantity_per_order: Array, - id: GraphQLTypes["ID"], + id: string, /** Account поставщика-владельца Offer'ов. */ offerer_account: string, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ offerer_name?: string | undefined | null, /** Партия поставки, по которой формируется приёмка. */ - shipment_id: GraphQLTypes["ID"], + shipment_id: string, status: GraphQLTypes["MarketplaceAplReceptionStatus"], supplier_signed_at?: GraphQLTypes["DateTime"] | undefined | null, /** Хэш транзакции подписи поставщика. */ @@ -47042,7 +47054,7 @@ export type GraphQLTypes = { }; ["MarketplaceAplReceptionByIdInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: GraphQLTypes["ID"] + apl_reception_id: string }; ["MarketplaceAplReceptionFactEntry"]: { __typename: "MarketplaceAplReceptionFactEntry", @@ -47050,7 +47062,7 @@ export type GraphQLTypes = { fact_quantity: number, /** Фактическая цена за единицу (если оператор скорректировал её при открытии приёмки). */ fact_unit_price?: string | undefined | null, - order_id: GraphQLTypes["ID"], + order_id: string, /** Наименование товара по этой позиции — для таблицы сверки в диалоге подписи. */ product_name?: string | undefined | null, /** Единица измерения товара по этой позиции (шт., кг, л, упак.). */ @@ -47061,7 +47073,7 @@ export type GraphQLTypes = { fact_quantity: number, /** Фактическая цена за единицу (оператор может изменить её при открытии приёмки). */ fact_unit_price?: string | undefined | null, - order_id: GraphQLTypes["ID"] + order_id: string }; ["MarketplaceAplReceptionResult"]: { __typename: "MarketplaceAplReceptionResult", @@ -47170,7 +47182,7 @@ export type GraphQLTypes = { }; ["MarketplaceAssignInventoryShelfInput"]: { /** Позиция склада, для которой назначается полка. */ - inventory_id: GraphQLTypes["ID"], + inventory_id: string, /** Полка/ячейка склада (свободная строка). Пусто — очистить полку. */ shelf?: string | undefined | null }; @@ -47300,7 +47312,7 @@ export type GraphQLTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: GraphQLTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, к которой привязывается отсканированный штрих-код. */ - inventory_id: GraphQLTypes["ID"] + inventory_id: string }; /** Экономика кооперативного участка: общий кошелёк членских взносов, плановые расходы с резервом на 30 дней, веса участников распределения и балансы персональных кошельков. */ ["MarketplaceBranchEconomy"]: { @@ -47335,7 +47347,7 @@ export type GraphQLTypes = { }; ["MarketplaceCancelStockOrderInput"]: { /** Заказ со склада кооператива, отменяемый до открытия выдачи. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Причина отмены (видна пайщику в истории заказа). */ reason?: string | undefined | null }; @@ -47508,7 +47520,7 @@ export type GraphQLTypes = { }; ["MarketplaceClearInventoryLabelInput"]: { /** Позиция склада, с которой снимается штрих-код (для переклейки). */ - inventory_id: GraphQLTypes["ID"] + inventory_id: string }; ["MarketplaceConfirmWriteoffInput"]: { /** Кооперативный участок, по которому подтверждается списание. */ @@ -47625,7 +47637,7 @@ export type GraphQLTypes = { /** Опционально для Варианта Б — фактически принятое количество per-Order. Для пропущенных Order'ов берётся order.quantity. */ fact_quantity_per_order?: Array | undefined | null, /** Партия поставки в статусе SUPPLY_PREPARED. */ - shipment_id: GraphQLTypes["ID"] + shipment_id: string }; ["MarketplaceCreateExpressReceptionInput"]: { /** КУ, на котором оператор принимает имущество. */ @@ -47667,7 +47679,7 @@ export type GraphQLTypes = { /** Фактическая цена за единицу (оператор мог скорректировать). */ actual_unit_price: string, /** Существующий заказ пайщика к выдаче этим бандлом. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Акт приёма-передачи, подписанный оператором КУ первой подписью. */ signiss1_act: GraphQLTypes["MarketplaceIssueActSignedDocumentInput"] }; @@ -47687,7 +47699,7 @@ export type GraphQLTypes = { }; ["MarketplaceCreateShipmentInput"]: { /** Идентификатор консолидированной заявки в статусе ACCEPTED. */ - cycle_id: GraphQLTypes["ID"], + cycle_id: string, /** Группы доставки по КУ заявки. Каждая группа = одна партия (один КУ, один вариант доставки, опционально подмножество заказов). Покрытие всех КУ заявки не требуется — можно формировать частично и догружать остаток отдельными партиями. */ groups: Array }; @@ -47709,7 +47721,7 @@ export type GraphQLTypes = { }; ["MarketplaceCreateStockProposalLineInput"]: { /** Предложение кооператива из остатка. */ - offer_id: GraphQLTypes["ID"], + offer_id: string, /** order_hash из подготовки (marketplaceStockIssuancePayloads). */ order_hash: string, /** Количество единиц. */ @@ -47840,7 +47852,7 @@ export type GraphQLTypes = { /** Строки докладки с подписью получения (signiss2) из marketplaceStockProposalSignablePayloads. */ order_lines: Array, /** Предложение со склада кооператива. */ - proposal_id: GraphQLTypes["ID"], + proposal_id: string, /** Единое подписанное Заявление о конвертации на всю сумму доплаты с паевого. Не передаётся, когда членских средств хватает. */ signed_convert?: GraphQLTypes["MarketplaceConvertStatementSignedInput"] | undefined | null }; @@ -47848,7 +47860,7 @@ export type GraphQLTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: GraphQLTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, на которую наклеивается штрих-код. */ - inventory_id: GraphQLTypes["ID"] + inventory_id: string }; /** Состояние геокодинга адреса: PENDING — в процессе, OK — успешно, FAILED — ошибка. */ ["MarketplaceGeocodeStatus"]: MarketplaceGeocodeStatus; @@ -47859,7 +47871,7 @@ export type GraphQLTypes = { }; ["MarketplaceGetShipmentInput"]: { /** Идентификатор партии поставки. */ - shipment_id: GraphQLTypes["ID"] + shipment_id: string }; ["MarketplaceInventoryItem"]: { __typename: "MarketplaceInventoryItem", @@ -47879,13 +47891,13 @@ export type GraphQLTypes = { delivery_point_name?: string | undefined | null, /** Срок годности имущества. По нему идёт списание просрочки — ключевой параметр контроля склада. Пусто — срок не задан. */ expiry_date?: GraphQLTypes["DateTime"] | undefined | null, - id: GraphQLTypes["ID"], + id: string, /** Момент маркировки штрих-кодом (если есть). */ labeled_at?: GraphQLTypes["DateTime"] | undefined | null, /** Оператор КУ, наклеивший штрих-код (если позиция промаркирована). */ labeled_by_operator_account?: string | undefined | null, /** Заказ, к которому относится позиция. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Заказчик — печатается на наклейке. */ orderer_account_snapshot: string, /** Фамилия Имя Отчество заказчика (организация — краткое наименование). Для показа в списках вместо служебного имени аккаунта. */ @@ -47895,7 +47907,7 @@ export type GraphQLTypes = { /** Наименование товара — для печатной наклейки. */ product_name_snapshot: string, /** Предложение кооператива, которым остаток опубликован в каталоге. Пусто — не опубликован. */ - published_offer_id?: GraphQLTypes["ID"] | undefined | null, + published_offer_id?: string | undefined | null, /** Количество единиц имущества в этой позиции склада. */ quantity_per_label: number, /** Момент приёмки имущества кооперативом по акту. */ @@ -47903,11 +47915,11 @@ export type GraphQLTypes = { /** Оператор КУ, оформивший приёмку. */ received_by_operator_account: string, /** Заказ со склада кооператива, под который позиция зарезервирована. Пусто — свободна. */ - reserved_order_id?: GraphQLTypes["ID"] | undefined | null, + reserved_order_id?: string | undefined | null, /** Полка/ячейка склада, куда положена позиция. Пусто — место не назначено. */ shelf?: string | undefined | null, /** Партия поставки, в составе которой имущество получено. */ - shipment_id: GraphQLTypes["ID"], + shipment_id: string, status: GraphQLTypes["MarketplaceInventoryStatus"], /** Единица измерения товара (шт./кг/литр/упак.) — из предложения. Для подписей количества на складе. */ unit_of_measure?: string | undefined | null, @@ -48086,9 +48098,9 @@ export type GraphQLTypes = { /** Фильтр по КУ. */ braname?: string | undefined | null, /** Фильтр по заказу. */ - order_id?: GraphQLTypes["ID"] | undefined | null, + order_id?: string | undefined | null, /** Фильтр по партии поставки. */ - shipment_id?: GraphQLTypes["ID"] | undefined | null, + shipment_id?: string | undefined | null, /** Фильтр по состояниям склада. */ statuses?: Array | undefined | null }; @@ -48151,7 +48163,7 @@ export type GraphQLTypes = { /** Фильтр по КУ-получателю. */ braname?: string | undefined | null, /** Фильтр по консолидированной заявке. */ - cycle_id?: GraphQLTypes["ID"] | undefined | null, + cycle_id?: string | undefined | null, /** Фильтр по статусам партий. */ statuses?: Array | undefined | null }; @@ -48374,6 +48386,8 @@ export type GraphQLTypes = { issuance_fact?: GraphQLTypes["MarketplaceOrderIssuanceFactSnapshot"] | undefined | null, /** Текстовая причина последнего изменения статуса. */ last_status_reason?: string | undefined | null, + /** Членский взнос, включённый в стоимость заказа, по ставке на момент оформления. Заказчик платит total_cost + membership_fee; пусто — заказ ещё не подтверждён блокчейном. */ + membership_fee?: string | undefined | null, /** Хеш предложения в блокчейне (snapshot на момент заказа). */ offer_hash: string, /** Идентификатор предложения, по которому оформлен заказ. */ @@ -48406,8 +48420,10 @@ export type GraphQLTypes = { supplier_account: string, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ supplier_name?: string | undefined | null, - /** Общая сумма заказа. */ + /** Общая сумма заказа (стоимость имущества без членского взноса). */ total_cost: string, + /** Полная сумма к оплате заказчиком: total_cost + membership_fee. Готовое значение — клиенту не нужно складывать поля самому. */ + total_cost_with_fee: string, /** Единица измерения товара из предложения (шт., кг, л, упак.). */ unit_of_measure?: string | undefined | null, /** Когда запись о заказе последний раз изменялась. */ @@ -48492,19 +48508,19 @@ export type GraphQLTypes = { /** Сумма платежа (numeric с 4 знаками). */ amount: string, /** Акт приёмки, по которому возникло обязательство. */ - apl_reception_id: GraphQLTypes["ID"], + apl_reception_id: string, completed_at?: GraphQLTypes["DateTime"] | undefined | null, coopname: string, /** Идентификатор связанного платежа в общем реестре кооператива — кассир видит выплату в общей ленте платежей. */ - core_payment_id?: GraphQLTypes["ID"] | undefined | null, + core_payment_id?: string | undefined | null, created_at: GraphQLTypes["DateTime"], /** Причина отказа банковского перевода, если кассир отказал в проведении. */ decline_reason?: string | undefined | null, - id: GraphQLTypes["ID"], + id: string, /** Хэш заказа в каталоге поставок — один заказ = одна выплата. */ order_hash: string, /** Идентификатор заказа в каталоге поставок. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Аккаунт поставщика — получатель выплаты. */ payee_account: string, /** Куда уходит выплата — короткая подпись реквизитов, например «Сбербанк •1234». */ @@ -48555,7 +48571,7 @@ export type GraphQLTypes = { }; ["MarketplacePublishStockInput"]: { /** Позиции свободного остатка склада для публикации в каталог. */ - inventory_ids: Array, + inventory_ids: Array, /** Цена за единицу при публикации. Пусто — цена прибытия; меньше цены прибытия — уценка. */ price_per_unit?: string | undefined | null }; @@ -48785,7 +48801,7 @@ export type GraphQLTypes = { }; ["MarketplaceResolveStockProposalInput"]: { /** Предложение со склада кооператива. */ - proposal_id: GraphQLTypes["ID"] + proposal_id: string }; /** Заявление пайщика на гарантийный возврат имущества (Эпик 7). */ ["MarketplaceReturnClaim"]: { @@ -49019,10 +49035,10 @@ export type GraphQLTypes = { coopname: string, created_at: GraphQLTypes["DateTime"], /** Идентификатор консолидированной заявки. */ - cycle_id: GraphQLTypes["ID"], + cycle_id: string, /** Выбранный вариант доставки. */ delivery_variant: GraphQLTypes["MarketplaceShipmentDeliveryVariant"], - id: GraphQLTypes["ID"], + id: string, /** Account поставщика-владельца Offer'ов. */ offerer_account: string, status: GraphQLTypes["MarketplaceShipmentStatus"], @@ -49044,21 +49060,21 @@ export type GraphQLTypes = { braname: string, delivery_variant: GraphQLTypes["MarketplaceShipmentDeliveryVariant"], /** Подмножество заказов этого КУ, реально погружаемых в партию (частичная отгрузка). Пусто → все акцептованные заказы КУ (поведение по умолчанию). Невключённые заказы остаются ACCEPTED и доступны для следующей партии. */ - order_ids?: Array | undefined | null, + order_ids?: Array | undefined | null, /** Поля ТТН — обязательны для Варианта Б. */ ttn_data?: GraphQLTypes["MarketplaceShipmentTTNDataInput"] | undefined | null }; ["MarketplaceShipmentLinePackaging"]: { __typename: "MarketplaceShipmentLinePackaging", /** Заказ партии, к которому относится упаковка. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Сколько единиц имущества в одной коробке. */ units_per_box: number, ['...on MarketplaceShipmentLinePackaging']: Omit }; ["MarketplaceShipmentLinePackagingInput"]: { /** Заказ партии, к которому относится упаковка. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Сколько единиц имущества в одной коробке. */ units_per_box: number }; @@ -49094,7 +49110,7 @@ export type GraphQLTypes = { }; ["MarketplaceSignAplReceptionInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: GraphQLTypes["ID"], + apl_reception_id: string, /** Подписанные клиентом акты приёмки — один документ на каждый Order группы. Backend верифицирует подпись и отправляет on-chain signsupp/signchair с этим документом. */ signed_documents: Array }; @@ -49104,7 +49120,7 @@ export type GraphQLTypes = { }; ["MarketplaceSplitInventoryInput"]: { /** Позиция склада, которую раскладывают по нескольким полкам. */ - inventory_id: GraphQLTypes["ID"], + inventory_id: string, /** Доли разбиения; сумма количеств обязана равняться количеству позиции. */ splits: Array }; @@ -49141,7 +49157,7 @@ export type GraphQLTypes = { ["MarketplaceStockIssuanceOperatorLine"]: { __typename: "MarketplaceStockIssuanceOperatorLine", /** Предложение кооператива из остатка. */ - offer_id: GraphQLTypes["ID"], + offer_id: string, /** Детерминированный order_hash будущего заказа из остатка. */ order_hash: string, /** Наименование товара. */ @@ -49168,8 +49184,8 @@ export type GraphQLTypes = { braname: string, created_at: GraphQLTypes["DateTime"], /** Заказы, созданные при принятии предложения. */ - created_order_ids: Array, - id: GraphQLTypes["ID"], + created_order_ids: Array, + id: string, /** Строки предложения. */ items: Array, /** Пайщик-адресат предложения. */ @@ -49186,7 +49202,7 @@ export type GraphQLTypes = { ["MarketplaceStockProposalAcceptResult"]: { __typename: "MarketplaceStockProposalAcceptResult", /** Созданные заказы со склада кооператива. */ - order_ids: Array, + order_ids: Array, proposal: GraphQLTypes["MarketplaceStockProposal"], ['...on MarketplaceStockProposalAcceptResult']: Omit }; @@ -49202,7 +49218,7 @@ export type GraphQLTypes = { ["MarketplaceStockProposalItem"]: { __typename: "MarketplaceStockProposalItem", /** Предложение кооператива из остатка. */ - offer_id: GraphQLTypes["ID"], + offer_id: string, /** Наименование товара. */ product_name: string, /** Предложенное количество единиц. */ @@ -49213,7 +49229,7 @@ export type GraphQLTypes = { }; ["MarketplaceStockProposalItemInput"]: { /** Предложение кооператива из опубликованного остатка. */ - offer_id: GraphQLTypes["ID"], + offer_id: string, /** Количество единиц, предлагаемое пайщику. */ quantity: number }; @@ -49313,7 +49329,7 @@ export type GraphQLTypes = { }; ["MarketplaceUnpublishStockInput"]: { /** Опубликованные позиции остатка, снимаемые с витрины. */ - inventory_ids: Array + inventory_ids: Array }; ["MarketplaceUnpublishStockResult"]: { __typename: "MarketplaceUnpublishStockResult", diff --git a/components/sdk/src/selectors/marketplace/orderSelector.ts b/components/sdk/src/selectors/marketplace/orderSelector.ts index f520572f595..57e15e3e64c 100644 --- a/components/sdk/src/selectors/marketplace/orderSelector.ts +++ b/components/sdk/src/selectors/marketplace/orderSelector.ts @@ -54,6 +54,8 @@ export const rawOrderSelector = { group_min_volume: true, price_per_unit: true, total_cost: true, + membership_fee: true, + total_cost_with_fee: true, cycle_id: true, checkout_id: true, shipment_id: true, diff --git a/components/sdk/src/zeus/const.ts b/components/sdk/src/zeus/const.ts index ac2d0817a73..3c167a3a81f 100644 --- a/components/sdk/src/zeus/const.ts +++ b/components/sdk/src/zeus/const.ts @@ -4847,13 +4847,13 @@ export const ReturnTypes: Record = { coopname:"String", created_at:"DateTime", created_by_operator_account:"String", - cycle_id:"ID", + cycle_id:"String", expeditor_data:"MarketplaceShipmentTTNData", fact_quantity_per_order:"MarketplaceAplReceptionFactEntry", - id:"ID", + id:"String", offerer_account:"String", offerer_name:"String", - shipment_id:"ID", + shipment_id:"String", status:"MarketplaceAplReceptionStatus", supplier_signed_at:"DateTime", supplier_signsupp_tx_hash:"String", @@ -4865,7 +4865,7 @@ export const ReturnTypes: Record = { MarketplaceAplReceptionFactEntry:{ fact_quantity:"Int", fact_unit_price:"String", - order_id:"ID", + order_id:"String", product_name:"String", unit_of_measure:"String" }, @@ -5116,21 +5116,21 @@ export const ReturnTypes: Record = { delivery_point_address:"String", delivery_point_name:"String", expiry_date:"DateTime", - id:"ID", + id:"String", labeled_at:"DateTime", labeled_by_operator_account:"String", - order_id:"ID", + order_id:"String", orderer_account_snapshot:"String", orderer_name:"String", ownership:"MarketplaceInventoryOwnership", product_name_snapshot:"String", - published_offer_id:"ID", + published_offer_id:"String", quantity_per_label:"Int", received_at:"DateTime", received_by_operator_account:"String", - reserved_order_id:"ID", + reserved_order_id:"String", shelf:"String", - shipment_id:"ID", + shipment_id:"String", status:"MarketplaceInventoryStatus", unit_of_measure:"String", updated_at:"DateTime" @@ -5263,6 +5263,7 @@ export const ReturnTypes: Record = { id:"String", issuance_fact:"MarketplaceOrderIssuanceFactSnapshot", last_status_reason:"String", + membership_fee:"String", offer_hash:"String", offer_id:"String", order_hash:"String", @@ -5280,6 +5281,7 @@ export const ReturnTypes: Record = { supplier_account:"String", supplier_name:"String", total_cost:"String", + total_cost_with_fee:"String", unit_of_measure:"String", updated_at:"DateTime", warehouse_quantity:"Int", @@ -5317,15 +5319,15 @@ export const ReturnTypes: Record = { }, MarketplaceOutgoingPaymentRequest:{ amount:"String", - apl_reception_id:"ID", + apl_reception_id:"String", completed_at:"DateTime", coopname:"String", - core_payment_id:"ID", + core_payment_id:"String", created_at:"DateTime", decline_reason:"String", - id:"ID", + id:"String", order_hash:"String", - order_id:"ID", + order_id:"String", payee_account:"String", payout_destination:"String", payout_tx_hash:"String", @@ -5507,9 +5509,9 @@ export const ReturnTypes: Record = { braname:"String", coopname:"String", created_at:"DateTime", - cycle_id:"ID", + cycle_id:"String", delivery_variant:"MarketplaceShipmentDeliveryVariant", - id:"ID", + id:"String", offerer_account:"String", status:"MarketplaceShipmentStatus", total_amount:"String", @@ -5519,7 +5521,7 @@ export const ReturnTypes: Record = { updated_at:"DateTime" }, MarketplaceShipmentLinePackaging:{ - order_id:"ID", + order_id:"String", units_per_box:"Int" }, MarketplaceShipmentTTNData:{ @@ -5544,7 +5546,7 @@ export const ReturnTypes: Record = { order_lines:"MarketplaceStockAcceptOrderLine" }, MarketplaceStockIssuanceOperatorLine:{ - offer_id:"ID", + offer_id:"String", order_hash:"String", product_name:"String", quantity:"Int", @@ -5554,8 +5556,8 @@ export const ReturnTypes: Record = { MarketplaceStockProposal:{ braname:"String", created_at:"DateTime", - created_order_ids:"ID", - id:"ID", + created_order_ids:"String", + id:"String", items:"MarketplaceStockProposalItem", member_account:"String", operator_account:"String", @@ -5564,7 +5566,7 @@ export const ReturnTypes: Record = { total_cost:"String" }, MarketplaceStockProposalAcceptResult:{ - order_ids:"ID", + order_ids:"String", proposal:"MarketplaceStockProposal" }, MarketplaceStockProposalCreatedEvent:{ @@ -5572,7 +5574,7 @@ export const ReturnTypes: Record = { proposal_id:"String" }, MarketplaceStockProposalItem:{ - offer_id:"ID", + offer_id:"String", product_name:"String", quantity:"Int", unit_price:"String" diff --git a/components/sdk/src/zeus/index.ts b/components/sdk/src/zeus/index.ts index 0d91baec1ae..5f985cd6564 100644 --- a/components/sdk/src/zeus/index.ts +++ b/components/sdk/src/zeus/index.ts @@ -7715,7 +7715,7 @@ export type ValueTypes = { }>; ["MarketplaceAplReceptionByIdInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ValueTypes["ID"] | Variable + apl_reception_id: string | Variable }; ["MarketplaceAplReceptionFactEntry"]: AliasType<{ /** Фактически принятое количество (для расхождений Варианта Б). */ @@ -7734,7 +7734,7 @@ export type ValueTypes = { fact_quantity: number | Variable, /** Фактическая цена за единицу (оператор может изменить её при открытии приёмки). */ fact_unit_price?: string | undefined | null | Variable, - order_id: ValueTypes["ID"] | Variable + order_id: string | Variable }; ["MarketplaceAplReceptionResult"]: AliasType<{ apl_reception?:ValueTypes["MarketplaceAplReception"], @@ -7843,7 +7843,7 @@ export type ValueTypes = { }; ["MarketplaceAssignInventoryShelfInput"]: { /** Позиция склада, для которой назначается полка. */ - inventory_id: ValueTypes["ID"] | Variable, + inventory_id: string | Variable, /** Полка/ячейка склада (свободная строка). Пусто — очистить полку. */ shelf?: string | undefined | null | Variable }; @@ -7973,7 +7973,7 @@ export type ValueTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ValueTypes["MarketplaceBarcodeFormat"] | undefined | null | Variable, /** Позиция склада, к которой привязывается отсканированный штрих-код. */ - inventory_id: ValueTypes["ID"] | Variable + inventory_id: string | Variable }; /** Экономика кооперативного участка: общий кошелёк членских взносов, плановые расходы с резервом на 30 дней, веса участников распределения и балансы персональных кошельков. */ ["MarketplaceBranchEconomy"]: AliasType<{ @@ -8008,7 +8008,7 @@ export type ValueTypes = { }>; ["MarketplaceCancelStockOrderInput"]: { /** Заказ со склада кооператива, отменяемый до открытия выдачи. */ - order_id: ValueTypes["ID"] | Variable, + order_id: string | Variable, /** Причина отмены (видна пайщику в истории заказа). */ reason?: string | undefined | null | Variable }; @@ -8181,7 +8181,7 @@ export type ValueTypes = { }; ["MarketplaceClearInventoryLabelInput"]: { /** Позиция склада, с которой снимается штрих-код (для переклейки). */ - inventory_id: ValueTypes["ID"] | Variable + inventory_id: string | Variable }; ["MarketplaceConfirmWriteoffInput"]: { /** Кооперативный участок, по которому подтверждается списание. */ @@ -8298,7 +8298,7 @@ export type ValueTypes = { /** Опционально для Варианта Б — фактически принятое количество per-Order. Для пропущенных Order'ов берётся order.quantity. */ fact_quantity_per_order?: Array | undefined | null | Variable, /** Партия поставки в статусе SUPPLY_PREPARED. */ - shipment_id: ValueTypes["ID"] | Variable + shipment_id: string | Variable }; ["MarketplaceCreateExpressReceptionInput"]: { /** КУ, на котором оператор принимает имущество. */ @@ -8340,7 +8340,7 @@ export type ValueTypes = { /** Фактическая цена за единицу (оператор мог скорректировать). */ actual_unit_price: string | Variable, /** Существующий заказ пайщика к выдаче этим бандлом. */ - order_id: ValueTypes["ID"] | Variable, + order_id: string | Variable, /** Акт приёма-передачи, подписанный оператором КУ первой подписью. */ signiss1_act: ValueTypes["MarketplaceIssueActSignedDocumentInput"] | Variable }; @@ -8360,7 +8360,7 @@ export type ValueTypes = { }; ["MarketplaceCreateShipmentInput"]: { /** Идентификатор консолидированной заявки в статусе ACCEPTED. */ - cycle_id: ValueTypes["ID"] | Variable, + cycle_id: string | Variable, /** Группы доставки по КУ заявки. Каждая группа = одна партия (один КУ, один вариант доставки, опционально подмножество заказов). Покрытие всех КУ заявки не требуется — можно формировать частично и догружать остаток отдельными партиями. */ groups: Array | Variable }; @@ -8382,7 +8382,7 @@ export type ValueTypes = { }; ["MarketplaceCreateStockProposalLineInput"]: { /** Предложение кооператива из остатка. */ - offer_id: ValueTypes["ID"] | Variable, + offer_id: string | Variable, /** order_hash из подготовки (marketplaceStockIssuancePayloads). */ order_hash: string | Variable, /** Количество единиц. */ @@ -8512,7 +8512,7 @@ export type ValueTypes = { /** Строки докладки с подписью получения (signiss2) из marketplaceStockProposalSignablePayloads. */ order_lines: Array | Variable, /** Предложение со склада кооператива. */ - proposal_id: ValueTypes["ID"] | Variable, + proposal_id: string | Variable, /** Единое подписанное Заявление о конвертации на всю сумму доплаты с паевого. Не передаётся, когда членских средств хватает. */ signed_convert?: ValueTypes["MarketplaceConvertStatementSignedInput"] | undefined | null | Variable }; @@ -8520,7 +8520,7 @@ export type ValueTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ValueTypes["MarketplaceBarcodeFormat"] | undefined | null | Variable, /** Позиция склада, на которую наклеивается штрих-код. */ - inventory_id: ValueTypes["ID"] | Variable + inventory_id: string | Variable }; /** Состояние геокодинга адреса: PENDING — в процессе, OK — успешно, FAILED — ошибка. */ ["MarketplaceGeocodeStatus"]:MarketplaceGeocodeStatus; @@ -8531,7 +8531,7 @@ export type ValueTypes = { }; ["MarketplaceGetShipmentInput"]: { /** Идентификатор партии поставки. */ - shipment_id: ValueTypes["ID"] | Variable + shipment_id: string | Variable }; ["MarketplaceInventoryItem"]: AliasType<{ /** Цена прибытия за единицу (закупочная из акта приёмки) — база цены публикации остатка. */ @@ -8758,9 +8758,9 @@ export type ValueTypes = { /** Фильтр по КУ. */ braname?: string | undefined | null | Variable, /** Фильтр по заказу. */ - order_id?: ValueTypes["ID"] | undefined | null | Variable, + order_id?: string | undefined | null | Variable, /** Фильтр по партии поставки. */ - shipment_id?: ValueTypes["ID"] | undefined | null | Variable, + shipment_id?: string | undefined | null | Variable, /** Фильтр по состояниям склада. */ statuses?: Array | undefined | null | Variable }; @@ -8823,7 +8823,7 @@ export type ValueTypes = { /** Фильтр по КУ-получателю. */ braname?: string | undefined | null | Variable, /** Фильтр по консолидированной заявке. */ - cycle_id?: ValueTypes["ID"] | undefined | null | Variable, + cycle_id?: string | undefined | null | Variable, /** Фильтр по статусам партий. */ statuses?: Array | undefined | null | Variable }; @@ -9045,6 +9045,8 @@ export type ValueTypes = { issuance_fact?:ValueTypes["MarketplaceOrderIssuanceFactSnapshot"], /** Текстовая причина последнего изменения статуса. */ last_status_reason?:boolean | `@${string}`, + /** Членский взнос, включённый в стоимость заказа, по ставке на момент оформления. Заказчик платит total_cost + membership_fee; пусто — заказ ещё не подтверждён блокчейном. */ + membership_fee?:boolean | `@${string}`, /** Хеш предложения в блокчейне (snapshot на момент заказа). */ offer_hash?:boolean | `@${string}`, /** Идентификатор предложения, по которому оформлен заказ. */ @@ -9077,8 +9079,10 @@ export type ValueTypes = { supplier_account?:boolean | `@${string}`, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ supplier_name?:boolean | `@${string}`, - /** Общая сумма заказа. */ + /** Общая сумма заказа (стоимость имущества без членского взноса). */ total_cost?:boolean | `@${string}`, + /** Полная сумма к оплате заказчиком: total_cost + membership_fee. Готовое значение — клиенту не нужно складывать поля самому. */ + total_cost_with_fee?:boolean | `@${string}`, /** Единица измерения товара из предложения (шт., кг, л, упак.). */ unit_of_measure?:boolean | `@${string}`, /** Когда запись о заказе последний раз изменялась. */ @@ -9227,7 +9231,7 @@ export type ValueTypes = { }>; ["MarketplacePublishStockInput"]: { /** Позиции свободного остатка склада для публикации в каталог. */ - inventory_ids: Array | Variable, + inventory_ids: Array | Variable, /** Цена за единицу при публикации. Пусто — цена прибытия; меньше цены прибытия — уценка. */ price_per_unit?: string | undefined | null | Variable }; @@ -9457,7 +9461,7 @@ export type ValueTypes = { }; ["MarketplaceResolveStockProposalInput"]: { /** Предложение со склада кооператива. */ - proposal_id: ValueTypes["ID"] | Variable + proposal_id: string | Variable }; /** Заявление пайщика на гарантийный возврат имущества (Эпик 7). */ ["MarketplaceReturnClaim"]: AliasType<{ @@ -9716,7 +9720,7 @@ export type ValueTypes = { braname: string | Variable, delivery_variant: ValueTypes["MarketplaceShipmentDeliveryVariant"] | Variable, /** Подмножество заказов этого КУ, реально погружаемых в партию (частичная отгрузка). Пусто → все акцептованные заказы КУ (поведение по умолчанию). Невключённые заказы остаются ACCEPTED и доступны для следующей партии. */ - order_ids?: Array | undefined | null | Variable, + order_ids?: Array | undefined | null | Variable, /** Поля ТТН — обязательны для Варианта Б. */ ttn_data?: ValueTypes["MarketplaceShipmentTTNDataInput"] | undefined | null | Variable }; @@ -9730,7 +9734,7 @@ export type ValueTypes = { }>; ["MarketplaceShipmentLinePackagingInput"]: { /** Заказ партии, к которому относится упаковка. */ - order_id: ValueTypes["ID"] | Variable, + order_id: string | Variable, /** Сколько единиц имущества в одной коробке. */ units_per_box: number | Variable }; @@ -9766,7 +9770,7 @@ export type ValueTypes = { }; ["MarketplaceSignAplReceptionInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ValueTypes["ID"] | Variable, + apl_reception_id: string | Variable, /** Подписанные клиентом акты приёмки — один документ на каждый Order группы. Backend верифицирует подпись и отправляет on-chain signsupp/signchair с этим документом. */ signed_documents: Array | Variable }; @@ -9776,7 +9780,7 @@ export type ValueTypes = { }; ["MarketplaceSplitInventoryInput"]: { /** Позиция склада, которую раскладывают по нескольким полкам. */ - inventory_id: ValueTypes["ID"] | Variable, + inventory_id: string | Variable, /** Доли разбиения; сумма количеств обязана равняться количеству позиции. */ splits: Array | Variable }; @@ -9885,7 +9889,7 @@ export type ValueTypes = { }>; ["MarketplaceStockProposalItemInput"]: { /** Предложение кооператива из опубликованного остатка. */ - offer_id: ValueTypes["ID"] | Variable, + offer_id: string | Variable, /** Количество единиц, предлагаемое пайщику. */ quantity: number | Variable }; @@ -9985,7 +9989,7 @@ export type ValueTypes = { }>; ["MarketplaceUnpublishStockInput"]: { /** Опубликованные позиции остатка, снимаемые с витрины. */ - inventory_ids: Array | Variable + inventory_ids: Array | Variable }; ["MarketplaceUnpublishStockResult"]: AliasType<{ /** Сколько позиций снято с публикации. */ @@ -20738,7 +20742,7 @@ export type ResolverInputTypes = { }>; ["MarketplaceAplReceptionByIdInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ResolverInputTypes["ID"] + apl_reception_id: string }; ["MarketplaceAplReceptionFactEntry"]: AliasType<{ /** Фактически принятое количество (для расхождений Варианта Б). */ @@ -20756,7 +20760,7 @@ export type ResolverInputTypes = { fact_quantity: number, /** Фактическая цена за единицу (оператор может изменить её при открытии приёмки). */ fact_unit_price?: string | undefined | null, - order_id: ResolverInputTypes["ID"] + order_id: string }; ["MarketplaceAplReceptionResult"]: AliasType<{ apl_reception?:ResolverInputTypes["MarketplaceAplReception"], @@ -20863,7 +20867,7 @@ export type ResolverInputTypes = { }; ["MarketplaceAssignInventoryShelfInput"]: { /** Позиция склада, для которой назначается полка. */ - inventory_id: ResolverInputTypes["ID"], + inventory_id: string, /** Полка/ячейка склада (свободная строка). Пусто — очистить полку. */ shelf?: string | undefined | null }; @@ -20987,7 +20991,7 @@ export type ResolverInputTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ResolverInputTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, к которой привязывается отсканированный штрих-код. */ - inventory_id: ResolverInputTypes["ID"] + inventory_id: string }; /** Экономика кооперативного участка: общий кошелёк членских взносов, плановые расходы с резервом на 30 дней, веса участников распределения и балансы персональных кошельков. */ ["MarketplaceBranchEconomy"]: AliasType<{ @@ -21020,7 +21024,7 @@ export type ResolverInputTypes = { }>; ["MarketplaceCancelStockOrderInput"]: { /** Заказ со склада кооператива, отменяемый до открытия выдачи. */ - order_id: ResolverInputTypes["ID"], + order_id: string, /** Причина отмены (видна пайщику в истории заказа). */ reason?: string | undefined | null }; @@ -21183,7 +21187,7 @@ export type ResolverInputTypes = { }; ["MarketplaceClearInventoryLabelInput"]: { /** Позиция склада, с которой снимается штрих-код (для переклейки). */ - inventory_id: ResolverInputTypes["ID"] + inventory_id: string }; ["MarketplaceConfirmWriteoffInput"]: { /** Кооперативный участок, по которому подтверждается списание. */ @@ -21297,7 +21301,7 @@ export type ResolverInputTypes = { /** Опционально для Варианта Б — фактически принятое количество per-Order. Для пропущенных Order'ов берётся order.quantity. */ fact_quantity_per_order?: Array | undefined | null, /** Партия поставки в статусе SUPPLY_PREPARED. */ - shipment_id: ResolverInputTypes["ID"] + shipment_id: string }; ["MarketplaceCreateExpressReceptionInput"]: { /** КУ, на котором оператор принимает имущество. */ @@ -21338,7 +21342,7 @@ export type ResolverInputTypes = { /** Фактическая цена за единицу (оператор мог скорректировать). */ actual_unit_price: string, /** Существующий заказ пайщика к выдаче этим бандлом. */ - order_id: ResolverInputTypes["ID"], + order_id: string, /** Акт приёма-передачи, подписанный оператором КУ первой подписью. */ signiss1_act: ResolverInputTypes["MarketplaceIssueActSignedDocumentInput"] }; @@ -21358,7 +21362,7 @@ export type ResolverInputTypes = { }; ["MarketplaceCreateShipmentInput"]: { /** Идентификатор консолидированной заявки в статусе ACCEPTED. */ - cycle_id: ResolverInputTypes["ID"], + cycle_id: string, /** Группы доставки по КУ заявки. Каждая группа = одна партия (один КУ, один вариант доставки, опционально подмножество заказов). Покрытие всех КУ заявки не требуется — можно формировать частично и догружать остаток отдельными партиями. */ groups: Array }; @@ -21379,7 +21383,7 @@ export type ResolverInputTypes = { }; ["MarketplaceCreateStockProposalLineInput"]: { /** Предложение кооператива из остатка. */ - offer_id: ResolverInputTypes["ID"], + offer_id: string, /** order_hash из подготовки (marketplaceStockIssuancePayloads). */ order_hash: string, /** Количество единиц. */ @@ -21505,7 +21509,7 @@ export type ResolverInputTypes = { /** Строки докладки с подписью получения (signiss2) из marketplaceStockProposalSignablePayloads. */ order_lines: Array, /** Предложение со склада кооператива. */ - proposal_id: ResolverInputTypes["ID"], + proposal_id: string, /** Единое подписанное Заявление о конвертации на всю сумму доплаты с паевого. Не передаётся, когда членских средств хватает. */ signed_convert?: ResolverInputTypes["MarketplaceConvertStatementSignedInput"] | undefined | null }; @@ -21513,7 +21517,7 @@ export type ResolverInputTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ResolverInputTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, на которую наклеивается штрих-код. */ - inventory_id: ResolverInputTypes["ID"] + inventory_id: string }; /** Состояние геокодинга адреса: PENDING — в процессе, OK — успешно, FAILED — ошибка. */ ["MarketplaceGeocodeStatus"]:MarketplaceGeocodeStatus; @@ -21524,7 +21528,7 @@ export type ResolverInputTypes = { }; ["MarketplaceGetShipmentInput"]: { /** Идентификатор партии поставки. */ - shipment_id: ResolverInputTypes["ID"] + shipment_id: string }; ["MarketplaceInventoryItem"]: AliasType<{ /** Цена прибытия за единицу (закупочная из акта приёмки) — база цены публикации остатка. */ @@ -21748,9 +21752,9 @@ export type ResolverInputTypes = { /** Фильтр по КУ. */ braname?: string | undefined | null, /** Фильтр по заказу. */ - order_id?: ResolverInputTypes["ID"] | undefined | null, + order_id?: string | undefined | null, /** Фильтр по партии поставки. */ - shipment_id?: ResolverInputTypes["ID"] | undefined | null, + shipment_id?: string | undefined | null, /** Фильтр по состояниям склада. */ statuses?: Array | undefined | null }; @@ -21813,7 +21817,7 @@ export type ResolverInputTypes = { /** Фильтр по КУ-получателю. */ braname?: string | undefined | null, /** Фильтр по консолидированной заявке. */ - cycle_id?: ResolverInputTypes["ID"] | undefined | null, + cycle_id?: string | undefined | null, /** Фильтр по статусам партий. */ statuses?: Array | undefined | null }; @@ -22025,6 +22029,8 @@ export type ResolverInputTypes = { issuance_fact?:ResolverInputTypes["MarketplaceOrderIssuanceFactSnapshot"], /** Текстовая причина последнего изменения статуса. */ last_status_reason?:boolean | `@${string}`, + /** Членский взнос, включённый в стоимость заказа, по ставке на момент оформления. Заказчик платит total_cost + membership_fee; пусто — заказ ещё не подтверждён блокчейном. */ + membership_fee?:boolean | `@${string}`, /** Хеш предложения в блокчейне (snapshot на момент заказа). */ offer_hash?:boolean | `@${string}`, /** Идентификатор предложения, по которому оформлен заказ. */ @@ -22057,8 +22063,10 @@ export type ResolverInputTypes = { supplier_account?:boolean | `@${string}`, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ supplier_name?:boolean | `@${string}`, - /** Общая сумма заказа. */ + /** Общая сумма заказа (стоимость имущества без членского взноса). */ total_cost?:boolean | `@${string}`, + /** Полная сумма к оплате заказчиком: total_cost + membership_fee. Готовое значение — клиенту не нужно складывать поля самому. */ + total_cost_with_fee?:boolean | `@${string}`, /** Единица измерения товара из предложения (шт., кг, л, упак.). */ unit_of_measure?:boolean | `@${string}`, /** Когда запись о заказе последний раз изменялась. */ @@ -22197,7 +22205,7 @@ export type ResolverInputTypes = { }>; ["MarketplacePublishStockInput"]: { /** Позиции свободного остатка склада для публикации в каталог. */ - inventory_ids: Array, + inventory_ids: Array, /** Цена за единицу при публикации. Пусто — цена прибытия; меньше цены прибытия — уценка. */ price_per_unit?: string | undefined | null }; @@ -22421,7 +22429,7 @@ export type ResolverInputTypes = { }; ["MarketplaceResolveStockProposalInput"]: { /** Предложение со склада кооператива. */ - proposal_id: ResolverInputTypes["ID"] + proposal_id: string }; /** Заявление пайщика на гарантийный возврат имущества (Эпик 7). */ ["MarketplaceReturnClaim"]: AliasType<{ @@ -22672,7 +22680,7 @@ export type ResolverInputTypes = { braname: string, delivery_variant: ResolverInputTypes["MarketplaceShipmentDeliveryVariant"], /** Подмножество заказов этого КУ, реально погружаемых в партию (частичная отгрузка). Пусто → все акцептованные заказы КУ (поведение по умолчанию). Невключённые заказы остаются ACCEPTED и доступны для следующей партии. */ - order_ids?: Array | undefined | null, + order_ids?: Array | undefined | null, /** Поля ТТН — обязательны для Варианта Б. */ ttn_data?: ResolverInputTypes["MarketplaceShipmentTTNDataInput"] | undefined | null }; @@ -22685,7 +22693,7 @@ export type ResolverInputTypes = { }>; ["MarketplaceShipmentLinePackagingInput"]: { /** Заказ партии, к которому относится упаковка. */ - order_id: ResolverInputTypes["ID"], + order_id: string, /** Сколько единиц имущества в одной коробке. */ units_per_box: number }; @@ -22720,7 +22728,7 @@ export type ResolverInputTypes = { }; ["MarketplaceSignAplReceptionInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ResolverInputTypes["ID"], + apl_reception_id: string, /** Подписанные клиентом акты приёмки — один документ на каждый Order группы. Backend верифицирует подпись и отправляет on-chain signsupp/signchair с этим документом. */ signed_documents: Array }; @@ -22730,7 +22738,7 @@ export type ResolverInputTypes = { }; ["MarketplaceSplitInventoryInput"]: { /** Позиция склада, которую раскладывают по нескольким полкам. */ - inventory_id: ResolverInputTypes["ID"], + inventory_id: string, /** Доли разбиения; сумма количеств обязана равняться количеству позиции. */ splits: Array }; @@ -22832,7 +22840,7 @@ export type ResolverInputTypes = { }>; ["MarketplaceStockProposalItemInput"]: { /** Предложение кооператива из опубликованного остатка. */ - offer_id: ResolverInputTypes["ID"], + offer_id: string, /** Количество единиц, предлагаемое пайщику. */ quantity: number }; @@ -22927,7 +22935,7 @@ export type ResolverInputTypes = { }>; ["MarketplaceUnpublishStockInput"]: { /** Опубликованные позиции остатка, снимаемые с витрины. */ - inventory_ids: Array + inventory_ids: Array }; ["MarketplaceUnpublishStockResult"]: AliasType<{ /** Сколько позиций снято с публикации. */ @@ -33347,18 +33355,18 @@ export type ModelTypes = { created_at: ModelTypes["DateTime"], created_by_operator_account: string, /** Консолидированная заявка. */ - cycle_id: ModelTypes["ID"], + cycle_id: string, /** Снапшот данных экспедитора + ТТН (только для Варианта Б). */ expeditor_data?: ModelTypes["MarketplaceShipmentTTNData"] | undefined | null, /** Фактически принятое количество per-Order. */ fact_quantity_per_order: Array, - id: ModelTypes["ID"], + id: string, /** Account поставщика-владельца Offer'ов. */ offerer_account: string, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ offerer_name?: string | undefined | null, /** Партия поставки, по которой формируется приёмка. */ - shipment_id: ModelTypes["ID"], + shipment_id: string, status: ModelTypes["MarketplaceAplReceptionStatus"], supplier_signed_at?: ModelTypes["DateTime"] | undefined | null, /** Хэш транзакции подписи поставщика. */ @@ -33372,14 +33380,14 @@ export type ModelTypes = { }; ["MarketplaceAplReceptionByIdInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ModelTypes["ID"] + apl_reception_id: string }; ["MarketplaceAplReceptionFactEntry"]: { /** Фактически принятое количество (для расхождений Варианта Б). */ fact_quantity: number, /** Фактическая цена за единицу (если оператор скорректировал её при открытии приёмки). */ fact_unit_price?: string | undefined | null, - order_id: ModelTypes["ID"], + order_id: string, /** Наименование товара по этой позиции — для таблицы сверки в диалоге подписи. */ product_name?: string | undefined | null, /** Единица измерения товара по этой позиции (шт., кг, л, упак.). */ @@ -33389,7 +33397,7 @@ export type ModelTypes = { fact_quantity: number, /** Фактическая цена за единицу (оператор может изменить её при открытии приёмки). */ fact_unit_price?: string | undefined | null, - order_id: ModelTypes["ID"] + order_id: string }; ["MarketplaceAplReceptionResult"]: { apl_reception: ModelTypes["MarketplaceAplReception"] @@ -33492,7 +33500,7 @@ export type ModelTypes = { }; ["MarketplaceAssignInventoryShelfInput"]: { /** Позиция склада, для которой назначается полка. */ - inventory_id: ModelTypes["ID"], + inventory_id: string, /** Полка/ячейка склада (свободная строка). Пусто — очистить полку. */ shelf?: string | undefined | null }; @@ -33607,7 +33615,7 @@ export type ModelTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ModelTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, к которой привязывается отсканированный штрих-код. */ - inventory_id: ModelTypes["ID"] + inventory_id: string }; /** Экономика кооперативного участка: общий кошелёк членских взносов, плановые расходы с резервом на 30 дней, веса участников распределения и балансы персональных кошельков. */ ["MarketplaceBranchEconomy"]: { @@ -33638,7 +33646,7 @@ export type ModelTypes = { }; ["MarketplaceCancelStockOrderInput"]: { /** Заказ со склада кооператива, отменяемый до открытия выдачи. */ - order_id: ModelTypes["ID"], + order_id: string, /** Причина отмены (видна пайщику в истории заказа). */ reason?: string | undefined | null }; @@ -33791,7 +33799,7 @@ export type ModelTypes = { }; ["MarketplaceClearInventoryLabelInput"]: { /** Позиция склада, с которой снимается штрих-код (для переклейки). */ - inventory_id: ModelTypes["ID"] + inventory_id: string }; ["MarketplaceConfirmWriteoffInput"]: { /** Кооперативный участок, по которому подтверждается списание. */ @@ -33901,7 +33909,7 @@ export type ModelTypes = { /** Опционально для Варианта Б — фактически принятое количество per-Order. Для пропущенных Order'ов берётся order.quantity. */ fact_quantity_per_order?: Array | undefined | null, /** Партия поставки в статусе SUPPLY_PREPARED. */ - shipment_id: ModelTypes["ID"] + shipment_id: string }; ["MarketplaceCreateExpressReceptionInput"]: { /** КУ, на котором оператор принимает имущество. */ @@ -33941,7 +33949,7 @@ export type ModelTypes = { /** Фактическая цена за единицу (оператор мог скорректировать). */ actual_unit_price: string, /** Существующий заказ пайщика к выдаче этим бандлом. */ - order_id: ModelTypes["ID"], + order_id: string, /** Акт приёма-передачи, подписанный оператором КУ первой подписью. */ signiss1_act: ModelTypes["MarketplaceIssueActSignedDocumentInput"] }; @@ -33961,7 +33969,7 @@ export type ModelTypes = { }; ["MarketplaceCreateShipmentInput"]: { /** Идентификатор консолидированной заявки в статусе ACCEPTED. */ - cycle_id: ModelTypes["ID"], + cycle_id: string, /** Группы доставки по КУ заявки. Каждая группа = одна партия (один КУ, один вариант доставки, опционально подмножество заказов). Покрытие всех КУ заявки не требуется — можно формировать частично и догружать остаток отдельными партиями. */ groups: Array }; @@ -33981,7 +33989,7 @@ export type ModelTypes = { }; ["MarketplaceCreateStockProposalLineInput"]: { /** Предложение кооператива из остатка. */ - offer_id: ModelTypes["ID"], + offer_id: string, /** order_hash из подготовки (marketplaceStockIssuancePayloads). */ order_hash: string, /** Количество единиц. */ @@ -34088,7 +34096,7 @@ export type ModelTypes = { /** Строки докладки с подписью получения (signiss2) из marketplaceStockProposalSignablePayloads. */ order_lines: Array, /** Предложение со склада кооператива. */ - proposal_id: ModelTypes["ID"], + proposal_id: string, /** Единое подписанное Заявление о конвертации на всю сумму доплаты с паевого. Не передаётся, когда членских средств хватает. */ signed_convert?: ModelTypes["MarketplaceConvertStatementSignedInput"] | undefined | null }; @@ -34096,7 +34104,7 @@ export type ModelTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: ModelTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, на которую наклеивается штрих-код. */ - inventory_id: ModelTypes["ID"] + inventory_id: string }; ["MarketplaceGeocodeStatus"]:MarketplaceGeocodeStatus; /** Параметры запроса одного заказа. */ @@ -34106,7 +34114,7 @@ export type ModelTypes = { }; ["MarketplaceGetShipmentInput"]: { /** Идентификатор партии поставки. */ - shipment_id: ModelTypes["ID"] + shipment_id: string }; ["MarketplaceInventoryItem"]: { /** Цена прибытия за единицу (закупочная из акта приёмки) — база цены публикации остатка. */ @@ -34125,13 +34133,13 @@ export type ModelTypes = { delivery_point_name?: string | undefined | null, /** Срок годности имущества. По нему идёт списание просрочки — ключевой параметр контроля склада. Пусто — срок не задан. */ expiry_date?: ModelTypes["DateTime"] | undefined | null, - id: ModelTypes["ID"], + id: string, /** Момент маркировки штрих-кодом (если есть). */ labeled_at?: ModelTypes["DateTime"] | undefined | null, /** Оператор КУ, наклеивший штрих-код (если позиция промаркирована). */ labeled_by_operator_account?: string | undefined | null, /** Заказ, к которому относится позиция. */ - order_id: ModelTypes["ID"], + order_id: string, /** Заказчик — печатается на наклейке. */ orderer_account_snapshot: string, /** Фамилия Имя Отчество заказчика (организация — краткое наименование). Для показа в списках вместо служебного имени аккаунта. */ @@ -34141,7 +34149,7 @@ export type ModelTypes = { /** Наименование товара — для печатной наклейки. */ product_name_snapshot: string, /** Предложение кооператива, которым остаток опубликован в каталоге. Пусто — не опубликован. */ - published_offer_id?: ModelTypes["ID"] | undefined | null, + published_offer_id?: string | undefined | null, /** Количество единиц имущества в этой позиции склада. */ quantity_per_label: number, /** Момент приёмки имущества кооперативом по акту. */ @@ -34149,11 +34157,11 @@ export type ModelTypes = { /** Оператор КУ, оформивший приёмку. */ received_by_operator_account: string, /** Заказ со склада кооператива, под который позиция зарезервирована. Пусто — свободна. */ - reserved_order_id?: ModelTypes["ID"] | undefined | null, + reserved_order_id?: string | undefined | null, /** Полка/ячейка склада, куда положена позиция. Пусто — место не назначено. */ shelf?: string | undefined | null, /** Партия поставки, в составе которой имущество получено. */ - shipment_id: ModelTypes["ID"], + shipment_id: string, status: ModelTypes["MarketplaceInventoryStatus"], /** Единица измерения товара (шт./кг/литр/упак.) — из предложения. Для подписей количества на складе. */ unit_of_measure?: string | undefined | null, @@ -34324,9 +34332,9 @@ export type ModelTypes = { /** Фильтр по КУ. */ braname?: string | undefined | null, /** Фильтр по заказу. */ - order_id?: ModelTypes["ID"] | undefined | null, + order_id?: string | undefined | null, /** Фильтр по партии поставки. */ - shipment_id?: ModelTypes["ID"] | undefined | null, + shipment_id?: string | undefined | null, /** Фильтр по состояниям склада. */ statuses?: Array | undefined | null }; @@ -34389,7 +34397,7 @@ export type ModelTypes = { /** Фильтр по КУ-получателю. */ braname?: string | undefined | null, /** Фильтр по консолидированной заявке. */ - cycle_id?: ModelTypes["ID"] | undefined | null, + cycle_id?: string | undefined | null, /** Фильтр по статусам партий. */ statuses?: Array | undefined | null }; @@ -34590,6 +34598,8 @@ export type ModelTypes = { issuance_fact?: ModelTypes["MarketplaceOrderIssuanceFactSnapshot"] | undefined | null, /** Текстовая причина последнего изменения статуса. */ last_status_reason?: string | undefined | null, + /** Членский взнос, включённый в стоимость заказа, по ставке на момент оформления. Заказчик платит total_cost + membership_fee; пусто — заказ ещё не подтверждён блокчейном. */ + membership_fee?: string | undefined | null, /** Хеш предложения в блокчейне (snapshot на момент заказа). */ offer_hash: string, /** Идентификатор предложения, по которому оформлен заказ. */ @@ -34622,8 +34632,10 @@ export type ModelTypes = { supplier_account: string, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ supplier_name?: string | undefined | null, - /** Общая сумма заказа. */ + /** Общая сумма заказа (стоимость имущества без членского взноса). */ total_cost: string, + /** Полная сумма к оплате заказчиком: total_cost + membership_fee. Готовое значение — клиенту не нужно складывать поля самому. */ + total_cost_with_fee: string, /** Единица измерения товара из предложения (шт., кг, л, упак.). */ unit_of_measure?: string | undefined | null, /** Когда запись о заказе последний раз изменялась. */ @@ -34694,19 +34706,19 @@ export type ModelTypes = { /** Сумма платежа (numeric с 4 знаками). */ amount: string, /** Акт приёмки, по которому возникло обязательство. */ - apl_reception_id: ModelTypes["ID"], + apl_reception_id: string, completed_at?: ModelTypes["DateTime"] | undefined | null, coopname: string, /** Идентификатор связанного платежа в общем реестре кооператива — кассир видит выплату в общей ленте платежей. */ - core_payment_id?: ModelTypes["ID"] | undefined | null, + core_payment_id?: string | undefined | null, created_at: ModelTypes["DateTime"], /** Причина отказа банковского перевода, если кассир отказал в проведении. */ decline_reason?: string | undefined | null, - id: ModelTypes["ID"], + id: string, /** Хэш заказа в каталоге поставок — один заказ = одна выплата. */ order_hash: string, /** Идентификатор заказа в каталоге поставок. */ - order_id: ModelTypes["ID"], + order_id: string, /** Аккаунт поставщика — получатель выплаты. */ payee_account: string, /** Куда уходит выплата — короткая подпись реквизитов, например «Сбербанк •1234». */ @@ -34749,7 +34761,7 @@ export type ModelTypes = { }; ["MarketplacePublishStockInput"]: { /** Позиции свободного остатка склада для публикации в каталог. */ - inventory_ids: Array, + inventory_ids: Array, /** Цена за единицу при публикации. Пусто — цена прибытия; меньше цены прибытия — уценка. */ price_per_unit?: string | undefined | null }; @@ -34967,7 +34979,7 @@ export type ModelTypes = { }; ["MarketplaceResolveStockProposalInput"]: { /** Предложение со склада кооператива. */ - proposal_id: ModelTypes["ID"] + proposal_id: string }; /** Заявление пайщика на гарантийный возврат имущества (Эпик 7). */ ["MarketplaceReturnClaim"]: { @@ -35183,10 +35195,10 @@ export type ModelTypes = { coopname: string, created_at: ModelTypes["DateTime"], /** Идентификатор консолидированной заявки. */ - cycle_id: ModelTypes["ID"], + cycle_id: string, /** Выбранный вариант доставки. */ delivery_variant: ModelTypes["MarketplaceShipmentDeliveryVariant"], - id: ModelTypes["ID"], + id: string, /** Account поставщика-владельца Offer'ов. */ offerer_account: string, status: ModelTypes["MarketplaceShipmentStatus"], @@ -35206,19 +35218,19 @@ export type ModelTypes = { braname: string, delivery_variant: ModelTypes["MarketplaceShipmentDeliveryVariant"], /** Подмножество заказов этого КУ, реально погружаемых в партию (частичная отгрузка). Пусто → все акцептованные заказы КУ (поведение по умолчанию). Невключённые заказы остаются ACCEPTED и доступны для следующей партии. */ - order_ids?: Array | undefined | null, + order_ids?: Array | undefined | null, /** Поля ТТН — обязательны для Варианта Б. */ ttn_data?: ModelTypes["MarketplaceShipmentTTNDataInput"] | undefined | null }; ["MarketplaceShipmentLinePackaging"]: { /** Заказ партии, к которому относится упаковка. */ - order_id: ModelTypes["ID"], + order_id: string, /** Сколько единиц имущества в одной коробке. */ units_per_box: number }; ["MarketplaceShipmentLinePackagingInput"]: { /** Заказ партии, к которому относится упаковка. */ - order_id: ModelTypes["ID"], + order_id: string, /** Сколько единиц имущества в одной коробке. */ units_per_box: number }; @@ -35251,7 +35263,7 @@ export type ModelTypes = { }; ["MarketplaceSignAplReceptionInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: ModelTypes["ID"], + apl_reception_id: string, /** Подписанные клиентом акты приёмки — один документ на каждый Order группы. Backend верифицирует подпись и отправляет on-chain signsupp/signchair с этим документом. */ signed_documents: Array }; @@ -35261,7 +35273,7 @@ export type ModelTypes = { }; ["MarketplaceSplitInventoryInput"]: { /** Позиция склада, которую раскладывают по нескольким полкам. */ - inventory_id: ModelTypes["ID"], + inventory_id: string, /** Доли разбиения; сумма количеств обязана равняться количеству позиции. */ splits: Array }; @@ -35293,7 +35305,7 @@ export type ModelTypes = { }; ["MarketplaceStockIssuanceOperatorLine"]: { /** Предложение кооператива из остатка. */ - offer_id: ModelTypes["ID"], + offer_id: string, /** Детерминированный order_hash будущего заказа из остатка. */ order_hash: string, /** Наименование товара. */ @@ -35318,8 +35330,8 @@ export type ModelTypes = { braname: string, created_at: ModelTypes["DateTime"], /** Заказы, созданные при принятии предложения. */ - created_order_ids: Array, - id: ModelTypes["ID"], + created_order_ids: Array, + id: string, /** Строки предложения. */ items: Array, /** Пайщик-адресат предложения. */ @@ -35334,7 +35346,7 @@ export type ModelTypes = { }; ["MarketplaceStockProposalAcceptResult"]: { /** Созданные заказы со склада кооператива. */ - order_ids: Array, + order_ids: Array, proposal: ModelTypes["MarketplaceStockProposal"] }; /** Оператор пункта выдачи предложил пайщику имущество со склада кооператива — требуется решение пайщика. */ @@ -35346,7 +35358,7 @@ export type ModelTypes = { }; ["MarketplaceStockProposalItem"]: { /** Предложение кооператива из остатка. */ - offer_id: ModelTypes["ID"], + offer_id: string, /** Наименование товара. */ product_name: string, /** Предложенное количество единиц. */ @@ -35356,7 +35368,7 @@ export type ModelTypes = { }; ["MarketplaceStockProposalItemInput"]: { /** Предложение кооператива из опубликованного остатка. */ - offer_id: ModelTypes["ID"], + offer_id: string, /** Количество единиц, предлагаемое пайщику. */ quantity: number }; @@ -35443,7 +35455,7 @@ export type ModelTypes = { }; ["MarketplaceUnpublishStockInput"]: { /** Опубликованные позиции остатка, снимаемые с витрины. */ - inventory_ids: Array + inventory_ids: Array }; ["MarketplaceUnpublishStockResult"]: { /** Сколько позиций снято с публикации. */ @@ -47016,18 +47028,18 @@ export type GraphQLTypes = { created_at: GraphQLTypes["DateTime"], created_by_operator_account: string, /** Консолидированная заявка. */ - cycle_id: GraphQLTypes["ID"], + cycle_id: string, /** Снапшот данных экспедитора + ТТН (только для Варианта Б). */ expeditor_data?: GraphQLTypes["MarketplaceShipmentTTNData"] | undefined | null, /** Фактически принятое количество per-Order. */ fact_quantity_per_order: Array, - id: GraphQLTypes["ID"], + id: string, /** Account поставщика-владельца Offer'ов. */ offerer_account: string, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ offerer_name?: string | undefined | null, /** Партия поставки, по которой формируется приёмка. */ - shipment_id: GraphQLTypes["ID"], + shipment_id: string, status: GraphQLTypes["MarketplaceAplReceptionStatus"], supplier_signed_at?: GraphQLTypes["DateTime"] | undefined | null, /** Хэш транзакции подписи поставщика. */ @@ -47042,7 +47054,7 @@ export type GraphQLTypes = { }; ["MarketplaceAplReceptionByIdInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: GraphQLTypes["ID"] + apl_reception_id: string }; ["MarketplaceAplReceptionFactEntry"]: { __typename: "MarketplaceAplReceptionFactEntry", @@ -47050,7 +47062,7 @@ export type GraphQLTypes = { fact_quantity: number, /** Фактическая цена за единицу (если оператор скорректировал её при открытии приёмки). */ fact_unit_price?: string | undefined | null, - order_id: GraphQLTypes["ID"], + order_id: string, /** Наименование товара по этой позиции — для таблицы сверки в диалоге подписи. */ product_name?: string | undefined | null, /** Единица измерения товара по этой позиции (шт., кг, л, упак.). */ @@ -47061,7 +47073,7 @@ export type GraphQLTypes = { fact_quantity: number, /** Фактическая цена за единицу (оператор может изменить её при открытии приёмки). */ fact_unit_price?: string | undefined | null, - order_id: GraphQLTypes["ID"] + order_id: string }; ["MarketplaceAplReceptionResult"]: { __typename: "MarketplaceAplReceptionResult", @@ -47170,7 +47182,7 @@ export type GraphQLTypes = { }; ["MarketplaceAssignInventoryShelfInput"]: { /** Позиция склада, для которой назначается полка. */ - inventory_id: GraphQLTypes["ID"], + inventory_id: string, /** Полка/ячейка склада (свободная строка). Пусто — очистить полку. */ shelf?: string | undefined | null }; @@ -47300,7 +47312,7 @@ export type GraphQLTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: GraphQLTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, к которой привязывается отсканированный штрих-код. */ - inventory_id: GraphQLTypes["ID"] + inventory_id: string }; /** Экономика кооперативного участка: общий кошелёк членских взносов, плановые расходы с резервом на 30 дней, веса участников распределения и балансы персональных кошельков. */ ["MarketplaceBranchEconomy"]: { @@ -47335,7 +47347,7 @@ export type GraphQLTypes = { }; ["MarketplaceCancelStockOrderInput"]: { /** Заказ со склада кооператива, отменяемый до открытия выдачи. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Причина отмены (видна пайщику в истории заказа). */ reason?: string | undefined | null }; @@ -47508,7 +47520,7 @@ export type GraphQLTypes = { }; ["MarketplaceClearInventoryLabelInput"]: { /** Позиция склада, с которой снимается штрих-код (для переклейки). */ - inventory_id: GraphQLTypes["ID"] + inventory_id: string }; ["MarketplaceConfirmWriteoffInput"]: { /** Кооперативный участок, по которому подтверждается списание. */ @@ -47625,7 +47637,7 @@ export type GraphQLTypes = { /** Опционально для Варианта Б — фактически принятое количество per-Order. Для пропущенных Order'ов берётся order.quantity. */ fact_quantity_per_order?: Array | undefined | null, /** Партия поставки в статусе SUPPLY_PREPARED. */ - shipment_id: GraphQLTypes["ID"] + shipment_id: string }; ["MarketplaceCreateExpressReceptionInput"]: { /** КУ, на котором оператор принимает имущество. */ @@ -47667,7 +47679,7 @@ export type GraphQLTypes = { /** Фактическая цена за единицу (оператор мог скорректировать). */ actual_unit_price: string, /** Существующий заказ пайщика к выдаче этим бандлом. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Акт приёма-передачи, подписанный оператором КУ первой подписью. */ signiss1_act: GraphQLTypes["MarketplaceIssueActSignedDocumentInput"] }; @@ -47687,7 +47699,7 @@ export type GraphQLTypes = { }; ["MarketplaceCreateShipmentInput"]: { /** Идентификатор консолидированной заявки в статусе ACCEPTED. */ - cycle_id: GraphQLTypes["ID"], + cycle_id: string, /** Группы доставки по КУ заявки. Каждая группа = одна партия (один КУ, один вариант доставки, опционально подмножество заказов). Покрытие всех КУ заявки не требуется — можно формировать частично и догружать остаток отдельными партиями. */ groups: Array }; @@ -47709,7 +47721,7 @@ export type GraphQLTypes = { }; ["MarketplaceCreateStockProposalLineInput"]: { /** Предложение кооператива из остатка. */ - offer_id: GraphQLTypes["ID"], + offer_id: string, /** order_hash из подготовки (marketplaceStockIssuancePayloads). */ order_hash: string, /** Количество единиц. */ @@ -47840,7 +47852,7 @@ export type GraphQLTypes = { /** Строки докладки с подписью получения (signiss2) из marketplaceStockProposalSignablePayloads. */ order_lines: Array, /** Предложение со склада кооператива. */ - proposal_id: GraphQLTypes["ID"], + proposal_id: string, /** Единое подписанное Заявление о конвертации на всю сумму доплаты с паевого. Не передаётся, когда членских средств хватает. */ signed_convert?: GraphQLTypes["MarketplaceConvertStatementSignedInput"] | undefined | null }; @@ -47848,7 +47860,7 @@ export type GraphQLTypes = { /** Формат штрих-кода. По умолчанию — EAN-13. */ format?: GraphQLTypes["MarketplaceBarcodeFormat"] | undefined | null, /** Позиция склада, на которую наклеивается штрих-код. */ - inventory_id: GraphQLTypes["ID"] + inventory_id: string }; /** Состояние геокодинга адреса: PENDING — в процессе, OK — успешно, FAILED — ошибка. */ ["MarketplaceGeocodeStatus"]: MarketplaceGeocodeStatus; @@ -47859,7 +47871,7 @@ export type GraphQLTypes = { }; ["MarketplaceGetShipmentInput"]: { /** Идентификатор партии поставки. */ - shipment_id: GraphQLTypes["ID"] + shipment_id: string }; ["MarketplaceInventoryItem"]: { __typename: "MarketplaceInventoryItem", @@ -47879,13 +47891,13 @@ export type GraphQLTypes = { delivery_point_name?: string | undefined | null, /** Срок годности имущества. По нему идёт списание просрочки — ключевой параметр контроля склада. Пусто — срок не задан. */ expiry_date?: GraphQLTypes["DateTime"] | undefined | null, - id: GraphQLTypes["ID"], + id: string, /** Момент маркировки штрих-кодом (если есть). */ labeled_at?: GraphQLTypes["DateTime"] | undefined | null, /** Оператор КУ, наклеивший штрих-код (если позиция промаркирована). */ labeled_by_operator_account?: string | undefined | null, /** Заказ, к которому относится позиция. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Заказчик — печатается на наклейке. */ orderer_account_snapshot: string, /** Фамилия Имя Отчество заказчика (организация — краткое наименование). Для показа в списках вместо служебного имени аккаунта. */ @@ -47895,7 +47907,7 @@ export type GraphQLTypes = { /** Наименование товара — для печатной наклейки. */ product_name_snapshot: string, /** Предложение кооператива, которым остаток опубликован в каталоге. Пусто — не опубликован. */ - published_offer_id?: GraphQLTypes["ID"] | undefined | null, + published_offer_id?: string | undefined | null, /** Количество единиц имущества в этой позиции склада. */ quantity_per_label: number, /** Момент приёмки имущества кооперативом по акту. */ @@ -47903,11 +47915,11 @@ export type GraphQLTypes = { /** Оператор КУ, оформивший приёмку. */ received_by_operator_account: string, /** Заказ со склада кооператива, под который позиция зарезервирована. Пусто — свободна. */ - reserved_order_id?: GraphQLTypes["ID"] | undefined | null, + reserved_order_id?: string | undefined | null, /** Полка/ячейка склада, куда положена позиция. Пусто — место не назначено. */ shelf?: string | undefined | null, /** Партия поставки, в составе которой имущество получено. */ - shipment_id: GraphQLTypes["ID"], + shipment_id: string, status: GraphQLTypes["MarketplaceInventoryStatus"], /** Единица измерения товара (шт./кг/литр/упак.) — из предложения. Для подписей количества на складе. */ unit_of_measure?: string | undefined | null, @@ -48086,9 +48098,9 @@ export type GraphQLTypes = { /** Фильтр по КУ. */ braname?: string | undefined | null, /** Фильтр по заказу. */ - order_id?: GraphQLTypes["ID"] | undefined | null, + order_id?: string | undefined | null, /** Фильтр по партии поставки. */ - shipment_id?: GraphQLTypes["ID"] | undefined | null, + shipment_id?: string | undefined | null, /** Фильтр по состояниям склада. */ statuses?: Array | undefined | null }; @@ -48151,7 +48163,7 @@ export type GraphQLTypes = { /** Фильтр по КУ-получателю. */ braname?: string | undefined | null, /** Фильтр по консолидированной заявке. */ - cycle_id?: GraphQLTypes["ID"] | undefined | null, + cycle_id?: string | undefined | null, /** Фильтр по статусам партий. */ statuses?: Array | undefined | null }; @@ -48374,6 +48386,8 @@ export type GraphQLTypes = { issuance_fact?: GraphQLTypes["MarketplaceOrderIssuanceFactSnapshot"] | undefined | null, /** Текстовая причина последнего изменения статуса. */ last_status_reason?: string | undefined | null, + /** Членский взнос, включённый в стоимость заказа, по ставке на момент оформления. Заказчик платит total_cost + membership_fee; пусто — заказ ещё не подтверждён блокчейном. */ + membership_fee?: string | undefined | null, /** Хеш предложения в блокчейне (snapshot на момент заказа). */ offer_hash: string, /** Идентификатор предложения, по которому оформлен заказ. */ @@ -48406,8 +48420,10 @@ export type GraphQLTypes = { supplier_account: string, /** Наименование поставщика (ФИО или название организации) — для экранов приёмки/подписи. */ supplier_name?: string | undefined | null, - /** Общая сумма заказа. */ + /** Общая сумма заказа (стоимость имущества без членского взноса). */ total_cost: string, + /** Полная сумма к оплате заказчиком: total_cost + membership_fee. Готовое значение — клиенту не нужно складывать поля самому. */ + total_cost_with_fee: string, /** Единица измерения товара из предложения (шт., кг, л, упак.). */ unit_of_measure?: string | undefined | null, /** Когда запись о заказе последний раз изменялась. */ @@ -48492,19 +48508,19 @@ export type GraphQLTypes = { /** Сумма платежа (numeric с 4 знаками). */ amount: string, /** Акт приёмки, по которому возникло обязательство. */ - apl_reception_id: GraphQLTypes["ID"], + apl_reception_id: string, completed_at?: GraphQLTypes["DateTime"] | undefined | null, coopname: string, /** Идентификатор связанного платежа в общем реестре кооператива — кассир видит выплату в общей ленте платежей. */ - core_payment_id?: GraphQLTypes["ID"] | undefined | null, + core_payment_id?: string | undefined | null, created_at: GraphQLTypes["DateTime"], /** Причина отказа банковского перевода, если кассир отказал в проведении. */ decline_reason?: string | undefined | null, - id: GraphQLTypes["ID"], + id: string, /** Хэш заказа в каталоге поставок — один заказ = одна выплата. */ order_hash: string, /** Идентификатор заказа в каталоге поставок. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Аккаунт поставщика — получатель выплаты. */ payee_account: string, /** Куда уходит выплата — короткая подпись реквизитов, например «Сбербанк •1234». */ @@ -48555,7 +48571,7 @@ export type GraphQLTypes = { }; ["MarketplacePublishStockInput"]: { /** Позиции свободного остатка склада для публикации в каталог. */ - inventory_ids: Array, + inventory_ids: Array, /** Цена за единицу при публикации. Пусто — цена прибытия; меньше цены прибытия — уценка. */ price_per_unit?: string | undefined | null }; @@ -48785,7 +48801,7 @@ export type GraphQLTypes = { }; ["MarketplaceResolveStockProposalInput"]: { /** Предложение со склада кооператива. */ - proposal_id: GraphQLTypes["ID"] + proposal_id: string }; /** Заявление пайщика на гарантийный возврат имущества (Эпик 7). */ ["MarketplaceReturnClaim"]: { @@ -49019,10 +49035,10 @@ export type GraphQLTypes = { coopname: string, created_at: GraphQLTypes["DateTime"], /** Идентификатор консолидированной заявки. */ - cycle_id: GraphQLTypes["ID"], + cycle_id: string, /** Выбранный вариант доставки. */ delivery_variant: GraphQLTypes["MarketplaceShipmentDeliveryVariant"], - id: GraphQLTypes["ID"], + id: string, /** Account поставщика-владельца Offer'ов. */ offerer_account: string, status: GraphQLTypes["MarketplaceShipmentStatus"], @@ -49044,21 +49060,21 @@ export type GraphQLTypes = { braname: string, delivery_variant: GraphQLTypes["MarketplaceShipmentDeliveryVariant"], /** Подмножество заказов этого КУ, реально погружаемых в партию (частичная отгрузка). Пусто → все акцептованные заказы КУ (поведение по умолчанию). Невключённые заказы остаются ACCEPTED и доступны для следующей партии. */ - order_ids?: Array | undefined | null, + order_ids?: Array | undefined | null, /** Поля ТТН — обязательны для Варианта Б. */ ttn_data?: GraphQLTypes["MarketplaceShipmentTTNDataInput"] | undefined | null }; ["MarketplaceShipmentLinePackaging"]: { __typename: "MarketplaceShipmentLinePackaging", /** Заказ партии, к которому относится упаковка. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Сколько единиц имущества в одной коробке. */ units_per_box: number, ['...on MarketplaceShipmentLinePackaging']: Omit }; ["MarketplaceShipmentLinePackagingInput"]: { /** Заказ партии, к которому относится упаковка. */ - order_id: GraphQLTypes["ID"], + order_id: string, /** Сколько единиц имущества в одной коробке. */ units_per_box: number }; @@ -49094,7 +49110,7 @@ export type GraphQLTypes = { }; ["MarketplaceSignAplReceptionInput"]: { /** Идентификатор акта приёмки. */ - apl_reception_id: GraphQLTypes["ID"], + apl_reception_id: string, /** Подписанные клиентом акты приёмки — один документ на каждый Order группы. Backend верифицирует подпись и отправляет on-chain signsupp/signchair с этим документом. */ signed_documents: Array }; @@ -49104,7 +49120,7 @@ export type GraphQLTypes = { }; ["MarketplaceSplitInventoryInput"]: { /** Позиция склада, которую раскладывают по нескольким полкам. */ - inventory_id: GraphQLTypes["ID"], + inventory_id: string, /** Доли разбиения; сумма количеств обязана равняться количеству позиции. */ splits: Array }; @@ -49141,7 +49157,7 @@ export type GraphQLTypes = { ["MarketplaceStockIssuanceOperatorLine"]: { __typename: "MarketplaceStockIssuanceOperatorLine", /** Предложение кооператива из остатка. */ - offer_id: GraphQLTypes["ID"], + offer_id: string, /** Детерминированный order_hash будущего заказа из остатка. */ order_hash: string, /** Наименование товара. */ @@ -49168,8 +49184,8 @@ export type GraphQLTypes = { braname: string, created_at: GraphQLTypes["DateTime"], /** Заказы, созданные при принятии предложения. */ - created_order_ids: Array, - id: GraphQLTypes["ID"], + created_order_ids: Array, + id: string, /** Строки предложения. */ items: Array, /** Пайщик-адресат предложения. */ @@ -49186,7 +49202,7 @@ export type GraphQLTypes = { ["MarketplaceStockProposalAcceptResult"]: { __typename: "MarketplaceStockProposalAcceptResult", /** Созданные заказы со склада кооператива. */ - order_ids: Array, + order_ids: Array, proposal: GraphQLTypes["MarketplaceStockProposal"], ['...on MarketplaceStockProposalAcceptResult']: Omit }; @@ -49202,7 +49218,7 @@ export type GraphQLTypes = { ["MarketplaceStockProposalItem"]: { __typename: "MarketplaceStockProposalItem", /** Предложение кооператива из остатка. */ - offer_id: GraphQLTypes["ID"], + offer_id: string, /** Наименование товара. */ product_name: string, /** Предложенное количество единиц. */ @@ -49213,7 +49229,7 @@ export type GraphQLTypes = { }; ["MarketplaceStockProposalItemInput"]: { /** Предложение кооператива из опубликованного остатка. */ - offer_id: GraphQLTypes["ID"], + offer_id: string, /** Количество единиц, предлагаемое пайщику. */ quantity: number }; @@ -49313,7 +49329,7 @@ export type GraphQLTypes = { }; ["MarketplaceUnpublishStockInput"]: { /** Опубликованные позиции остатка, снимаемые с витрины. */ - inventory_ids: Array + inventory_ids: Array }; ["MarketplaceUnpublishStockResult"]: { __typename: "MarketplaceUnpublishStockResult", -- 2.52.0 From 5dd65c5de73bbe757afb4e1aff9c632c97dc6aff Mon Sep 17 00:00:00 2001 From: ant Date: Tue, 21 Jul 2026 08:44:18 +0000 Subject: [PATCH 2/3] =?UTF-8?q?[598-51][@ant]=20fix:=20=D0=BF=D0=BE=D1=87?= =?UTF-8?q?=D0=B8=D0=BD=D0=B8=D1=82=D1=8C=20unit-=D1=82=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D1=8B=20marketplace=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BC=D0=B5=D0=BD=D1=8B=20whitelist=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B5=D1=81=D1=82=D1=80=20=D0=BF=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=B2=D1=89=D0=B8=D0=BA=D0=BE=D0=B2=20=E2=80=94=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D0=BE=D1=80?= =?UTF-8?q?=D1=8B=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=BD=D0=B0=D0=B1=D1=80=D0=B0=D0=BB=D0=B8=20=D0=BD=D0=BE=D0=B2?= =?UTF-8?q?=D1=8B=D0=B5=20=D0=BE=D0=B1=D1=8F=D0=B7=D0=B0=D1=82=D0=B5=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D1=80=D1=8B=20=D0=BF=D1=80=D0=B8=20=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=B5=20PR=20#152,=20=D0=BC=D0=BE=D0=BA=D0=B8=20=D0=BD?= =?UTF-8?q?=D0=B5=20=D0=BE=D0=B1=D0=BD=D0=BE=D0=B2=D0=B8=D0=BB=D0=B8=20?= =?UTF-8?q?=D0=B8=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=BD=D0=B5=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=BF=D0=B8=D0=BB=D0=B8=D1=80=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D1=81=D1=8C;=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20spec=20=D0=B4=D0=BB=D1=8F=20MarketplaceSup?= =?UTF-8?q?plierRegistryService=20=D0=B2=D0=B7=D0=B0=D0=BC=D0=B5=D0=BD=20?= =?UTF-8?q?=D1=83=D0=B4=D0=B0=D0=BB=D1=91=D0=BD=D0=BD=D0=BE=D0=B3=D0=BE=20?= =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D0=B0=20=D0=BD=D0=B5=D1=81=D1=83=D1=89?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=B2=D1=83=D1=8E=D1=89=D0=B5=D0=B3=D0=BE=20?= =?UTF-8?q?=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../marketplace-apl-reception.service.spec.ts | 9 + ...ketplace-supplier-registry.service.spec.ts | 325 ++++++++++++++++++ .../marketplace-writeoff.service.spec.ts | 27 +- ...etplace-inventory-resolver-scoping.test.ts | 10 +- .../marketplace-membership-guard.test.ts | 37 +- .../marketplace-moderation-service.test.ts | 2 + ...marketplace-offer-counters-service.test.ts | 2 + .../marketplace-whitelist-service.test.ts | 161 --------- 8 files changed, 392 insertions(+), 181 deletions(-) create mode 100644 components/controller/src/extensions/marketplace/application/services/marketplace-supplier-registry.service.spec.ts delete mode 100644 components/controller/tests/unit/marketplace/marketplace-whitelist-service.test.ts diff --git a/components/controller/src/extensions/marketplace/application/services/marketplace-apl-reception.service.spec.ts b/components/controller/src/extensions/marketplace/application/services/marketplace-apl-reception.service.spec.ts index 17ae9fc399f..b4e5ce4dbf1 100644 --- a/components/controller/src/extensions/marketplace/application/services/marketplace-apl-reception.service.spec.ts +++ b/components/controller/src/extensions/marketplace/application/services/marketplace-apl-reception.service.spec.ts @@ -123,6 +123,13 @@ function buildMocks() { resolvePayoutMethod: jest.fn().mockResolvedValue(null), } as any; + // Реквизиты договора поставщика для назначения платежа в initiatePayouts + // (см. MarketplaceSupplierRegistryService.findByMember). По умолчанию — + // «нет записи»: buildPayoutPurpose падает на fallback-текст без реквизитов. + const supplierRegistry = { + findByMember: jest.fn().mockResolvedValue(null), + } as any; + const supplierActionService = { declineOrdersAtReception: jest.fn().mockResolvedValue([]), } as any; @@ -147,6 +154,7 @@ function buildMocks() { inventoryRepo, coreGateway, supplierSettings, + supplierRegistry, supplierActionService, documentDomainService, logger, @@ -166,6 +174,7 @@ function buildService(mocks: ReturnType): MarketplaceAplRecep { symbol: 'RUB', decimals: 4 }, mocks.coreGateway, mocks.supplierSettings, + mocks.supplierRegistry, mocks.supplierActionService, mocks.documentDomainService, new EventEmitter2(), diff --git a/components/controller/src/extensions/marketplace/application/services/marketplace-supplier-registry.service.spec.ts b/components/controller/src/extensions/marketplace/application/services/marketplace-supplier-registry.service.spec.ts new file mode 100644 index 00000000000..549ac56e943 --- /dev/null +++ b/components/controller/src/extensions/marketplace/application/services/marketplace-supplier-registry.service.spec.ts @@ -0,0 +1,325 @@ +/** + * Unit-тесты MarketplaceSupplierRegistryService. + * + * Заменяет удалённый MarketplaceWhitelistService (PR #152, [598-51]) — тот + * тестировал упразднённую концепцию whitelist (открытая витрина / по списку), + * которой в коде больше нет. Реестр поставщиков — другая модель: заявка → + * рассмотрение → APPROVED/REJECTED, допуск офферера строго по статусу. + * + * Покрывают: + * - isOfferer: сам кооператив всегда true (без похода в репозиторий), + * APPROVED → true, PENDING/REJECTED/нет записи → false, cache hit; + * - requestMembership: создание PENDING, идемпотентность повторной заявки, + * конфликт на уже APPROVED, переоткрытие REJECTED с новыми реквизитами; + * - addSupplier: upsert (create при отсутствии / patch при наличии) сразу в APPROVED; + * - approve/reject: патчат статус, инвалидируют isOfferer-кеш; + * - switchModel: SHARE — заглушка (ConflictException), MEMBERSHIP — сброс в PENDING. + */ +import { ConflictException } from '@nestjs/common'; +import { MarketplaceSupplierRegistryService } from './marketplace-supplier-registry.service'; +import { MarketplaceSupplierDomainEntity } from '../../domain/entities/marketplace-supplier.entity'; +import { + MarketplaceSupplierModel, + MarketplaceSupplierStatus, +} from '../../domain/entities/marketplace-supplier.types'; +import type { MarketplaceSupplierDomainRepository } from '../../domain/repositories/marketplace-supplier.repository'; + +const COOP = 'voskhod'; + +function makeSupplier( + member: string, + status: MarketplaceSupplierStatus, + overrides: Partial<{ + model: MarketplaceSupplierModel; + contract_number: string | null; + contract_date: string | null; + reviewed_by: string | null; + reviewed_at: Date | null; + }> = {} +): MarketplaceSupplierDomainEntity { + return new MarketplaceSupplierDomainEntity({ + id: `id-${member}`, + coopname: COOP, + member_account: member, + model: overrides.model ?? MarketplaceSupplierModel.MEMBERSHIP, + status, + contract_number: overrides.contract_number ?? '17/2026', + contract_date: overrides.contract_date ?? '2026-05-01', + contract_document_url: null, + requested_by: member, + requested_at: new Date('2026-05-01T00:00:00Z'), + reviewed_by: overrides.reviewed_by ?? null, + reviewed_at: overrides.reviewed_at ?? null, + }); +} + +function makeRepo(): jest.Mocked { + return { + list: jest.fn(), + findByMember: jest.fn(), + create: jest.fn(), + patch: jest.fn(), + remove: jest.fn(), + }; +} + +function makeEventBus() { + return { emit: jest.fn() } as unknown as import('@nestjs/event-emitter').EventEmitter2; +} + +describe('MarketplaceSupplierRegistryService', () => { + describe('isOfferer', () => { + it('сам кооператив → true без обращения к репозиторию (перепоставка остатков FR5)', async () => { + const repo = makeRepo(); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + await expect(service.isOfferer(COOP, COOP)).resolves.toBe(true); + expect(repo.findByMember).not.toHaveBeenCalled(); + }); + + it('запись APPROVED → true', async () => { + const repo = makeRepo(); + repo.findByMember.mockResolvedValue(makeSupplier('alice', MarketplaceSupplierStatus.APPROVED)); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + await expect(service.isOfferer(COOP, 'alice')).resolves.toBe(true); + }); + + it('запись PENDING → false (ещё не одобрен)', async () => { + const repo = makeRepo(); + repo.findByMember.mockResolvedValue(makeSupplier('alice', MarketplaceSupplierStatus.PENDING)); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + await expect(service.isOfferer(COOP, 'alice')).resolves.toBe(false); + }); + + it('записи нет → false', async () => { + const repo = makeRepo(); + repo.findByMember.mockResolvedValue(null); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + await expect(service.isOfferer(COOP, 'ghost')).resolves.toBe(false); + }); + + it('второй вызов того же пайщика — cache hit, repo не дёргается повторно', async () => { + const repo = makeRepo(); + repo.findByMember.mockResolvedValue(makeSupplier('alice', MarketplaceSupplierStatus.APPROVED)); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + await service.isOfferer(COOP, 'alice'); + await service.isOfferer(COOP, 'alice'); + expect(repo.findByMember).toHaveBeenCalledTimes(1); + }); + }); + + describe('requestMembership', () => { + it('без существующей записи → создаёт PENDING и эмитит уведомление председателю', async () => { + const repo = makeRepo(); + repo.findByMember.mockResolvedValue(null); + repo.create.mockResolvedValue(makeSupplier('bob', MarketplaceSupplierStatus.PENDING)); + const eventBus = makeEventBus(); + const service = new MarketplaceSupplierRegistryService(repo, eventBus); + + const result = await service.requestMembership(COOP, 'bob', '17/2026', '2026-05-01'); + + expect(result.status).toBe(MarketplaceSupplierStatus.PENDING); + expect(repo.create).toHaveBeenCalledWith( + expect.objectContaining({ + coopname: COOP, + member_account: 'bob', + status: MarketplaceSupplierStatus.PENDING, + contract_number: '17/2026', + contract_date: '2026-05-01', + }) + ); + expect(eventBus.emit).toHaveBeenCalledTimes(1); + }); + + it('уже поданная PENDING-заявка → идемпотентна, возвращает существующую без повторной записи', async () => { + const repo = makeRepo(); + const pending = makeSupplier('bob', MarketplaceSupplierStatus.PENDING); + repo.findByMember.mockResolvedValue(pending); + const eventBus = makeEventBus(); + const service = new MarketplaceSupplierRegistryService(repo, eventBus); + + const result = await service.requestMembership(COOP, 'bob', '17/2026', '2026-05-01'); + + expect(result).toBe(pending); + expect(repo.create).not.toHaveBeenCalled(); + expect(repo.patch).not.toHaveBeenCalled(); + expect(eventBus.emit).not.toHaveBeenCalled(); + }); + + it('уже APPROVED → 409 Conflict, повторная заявка запрещена', async () => { + const repo = makeRepo(); + repo.findByMember.mockResolvedValue(makeSupplier('bob', MarketplaceSupplierStatus.APPROVED)); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + await expect(service.requestMembership(COOP, 'bob', '17/2026', '2026-05-01')).rejects.toThrow( + ConflictException + ); + expect(repo.patch).not.toHaveBeenCalled(); + }); + + it('REJECTED → переоткрывает заявку в PENDING с новыми реквизитами договора', async () => { + const repo = makeRepo(); + repo.findByMember.mockResolvedValue(makeSupplier('bob', MarketplaceSupplierStatus.REJECTED)); + repo.patch.mockResolvedValue( + makeSupplier('bob', MarketplaceSupplierStatus.PENDING, { + contract_number: '18/2026', + contract_date: '2026-06-01', + }) + ); + const eventBus = makeEventBus(); + const service = new MarketplaceSupplierRegistryService(repo, eventBus); + + const result = await service.requestMembership(COOP, 'bob', '18/2026', '2026-06-01'); + + expect(repo.patch).toHaveBeenCalledWith( + COOP, + 'bob', + expect.objectContaining({ + status: MarketplaceSupplierStatus.PENDING, + contract_number: '18/2026', + contract_date: '2026-06-01', + reviewed_by: null, + reviewed_at: null, + }) + ); + expect(result.contract_number).toBe('18/2026'); + expect(eventBus.emit).toHaveBeenCalledTimes(1); + }); + }); + + describe('addSupplier (путь 2 — прямое добавление администратором)', () => { + it('без существующей записи → создаёт сразу APPROVED', async () => { + const repo = makeRepo(); + repo.findByMember.mockResolvedValue(null); + repo.create.mockResolvedValue(makeSupplier('carl', MarketplaceSupplierStatus.APPROVED)); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + const result = await service.addSupplier( + COOP, + 'carl', + MarketplaceSupplierModel.MEMBERSHIP, + '19/2026', + '2026-06-10', + 'chairman1' + ); + + expect(result.status).toBe(MarketplaceSupplierStatus.APPROVED); + expect(repo.create).toHaveBeenCalledWith( + expect.objectContaining({ status: MarketplaceSupplierStatus.APPROVED, requested_by: 'chairman1', reviewed_by: 'chairman1' }) + ); + expect(repo.patch).not.toHaveBeenCalled(); + }); + + it('с существующей записью → upsert через patch в APPROVED', async () => { + const repo = makeRepo(); + repo.findByMember.mockResolvedValue(makeSupplier('carl', MarketplaceSupplierStatus.REJECTED)); + repo.patch.mockResolvedValue(makeSupplier('carl', MarketplaceSupplierStatus.APPROVED)); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + await service.addSupplier(COOP, 'carl', MarketplaceSupplierModel.MEMBERSHIP, '20/2026', '2026-06-11', 'chairman1'); + + expect(repo.patch).toHaveBeenCalledWith( + COOP, + 'carl', + expect.objectContaining({ status: MarketplaceSupplierStatus.APPROVED, reviewed_by: 'chairman1' }) + ); + expect(repo.create).not.toHaveBeenCalled(); + }); + + it('инвалидирует isOfferer-кеш кооператива', async () => { + const repo = makeRepo(); + repo.findByMember.mockResolvedValueOnce(null); // прогрев кеша isOfferer('dave') → false + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + await expect(service.isOfferer(COOP, 'dave')).resolves.toBe(false); + + repo.findByMember.mockResolvedValueOnce(null); // addSupplier сам ищет существующую запись + repo.create.mockResolvedValue(makeSupplier('dave', MarketplaceSupplierStatus.APPROVED)); + await service.addSupplier(COOP, 'dave', MarketplaceSupplierModel.MEMBERSHIP, '21/2026', '2026-06-12', 'chairman1'); + + repo.findByMember.mockResolvedValueOnce(makeSupplier('dave', MarketplaceSupplierStatus.APPROVED)); + await expect(service.isOfferer(COOP, 'dave')).resolves.toBe(true); + // Без инвалидации второй вызов взял бы старое значение из кеша (false) без похода в repo. + expect(repo.findByMember).toHaveBeenCalledTimes(3); + }); + }); + + describe('approve / reject', () => { + it('approve патчит статус в APPROVED', async () => { + const repo = makeRepo(); + repo.patch.mockResolvedValue(makeSupplier('eve', MarketplaceSupplierStatus.APPROVED)); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + const result = await service.approve(COOP, 'eve', 'chairman1'); + + expect(result.status).toBe(MarketplaceSupplierStatus.APPROVED); + expect(repo.patch).toHaveBeenCalledWith( + COOP, + 'eve', + expect.objectContaining({ status: MarketplaceSupplierStatus.APPROVED, reviewed_by: 'chairman1' }) + ); + }); + + it('reject патчит статус в REJECTED', async () => { + const repo = makeRepo(); + repo.patch.mockResolvedValue(makeSupplier('eve', MarketplaceSupplierStatus.REJECTED)); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + const result = await service.reject(COOP, 'eve', 'chairman1'); + + expect(result.status).toBe(MarketplaceSupplierStatus.REJECTED); + expect(repo.patch).toHaveBeenCalledWith( + COOP, + 'eve', + expect.objectContaining({ status: MarketplaceSupplierStatus.REJECTED, reviewed_by: 'chairman1' }) + ); + }); + }); + + describe('switchModel', () => { + it('SHARE — заглушка, 409 Conflict, репозиторий не трогается', async () => { + const repo = makeRepo(); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + await expect( + service.switchModel(COOP, 'alice', MarketplaceSupplierModel.SHARE, null, null) + ).rejects.toThrow(ConflictException); + expect(repo.patch).not.toHaveBeenCalled(); + }); + + it('MEMBERSHIP — сбрасывает запись в PENDING с новым договором', async () => { + const repo = makeRepo(); + repo.patch.mockResolvedValue( + makeSupplier('alice', MarketplaceSupplierStatus.PENDING, { + model: MarketplaceSupplierModel.MEMBERSHIP, + }) + ); + const service = new MarketplaceSupplierRegistryService(repo, makeEventBus()); + + const result = await service.switchModel( + COOP, + 'alice', + MarketplaceSupplierModel.MEMBERSHIP, + '22/2026', + '2026-06-15' + ); + + expect(result.status).toBe(MarketplaceSupplierStatus.PENDING); + expect(repo.patch).toHaveBeenCalledWith( + COOP, + 'alice', + expect.objectContaining({ + model: MarketplaceSupplierModel.MEMBERSHIP, + status: MarketplaceSupplierStatus.PENDING, + contract_number: '22/2026', + contract_date: '2026-06-15', + reviewed_by: null, + reviewed_at: null, + }) + ); + }); + }); +}); diff --git a/components/controller/src/extensions/marketplace/application/services/marketplace-writeoff.service.spec.ts b/components/controller/src/extensions/marketplace/application/services/marketplace-writeoff.service.spec.ts index b3ac8cb620d..efb19583069 100644 --- a/components/controller/src/extensions/marketplace/application/services/marketplace-writeoff.service.spec.ts +++ b/components/controller/src/extensions/marketplace/application/services/marketplace-writeoff.service.spec.ts @@ -87,6 +87,17 @@ function buildMocks() { applyStatusTransition: jest.fn(), } as unknown as jest.Mocked; + // Обогащение позиций списания названием товара/заказа и адресом КУ + // (см. MarketplaceOrderDisplayService.resolveBranchDisplay) — по умолчанию + // «нет данных», тесты бизнес-логики списания эти поля не проверяют. + const orderRepo = { findById: jest.fn().mockResolvedValue(null) } as any; + const offerRepo = { findById: jest.fn().mockResolvedValue(null) } as any; + const orderDisplay = { + resolveBranchDisplay: jest + .fn() + .mockResolvedValue({ name: null, address: null, lat: null, lng: null }), + } as any; + const chainPort: jest.Mocked = { propWroff: jest.fn().mockResolvedValue({ transaction: { id: 'tx-prop' } } as any), execWroff: jest.fn().mockResolvedValue({ transaction: { id: 'tx-exec' } } as any), @@ -105,16 +116,30 @@ function buildMocks() { error: jest.fn(), } as any; - return { repo, inventoryRepo, chainPort, assetConfig, documentDomainService, eventBus, logger }; + return { + repo, + inventoryRepo, + orderRepo, + offerRepo, + chainPort, + assetConfig, + documentDomainService, + orderDisplay, + eventBus, + logger, + }; } function buildService(mocks: ReturnType): MarketplaceWriteoffService { return new MarketplaceWriteoffService( mocks.repo, mocks.inventoryRepo, + mocks.orderRepo, + mocks.offerRepo, mocks.chainPort, mocks.assetConfig, mocks.documentDomainService, + mocks.orderDisplay, mocks.eventBus, mocks.logger ); diff --git a/components/controller/tests/unit/marketplace/marketplace-inventory-resolver-scoping.test.ts b/components/controller/tests/unit/marketplace/marketplace-inventory-resolver-scoping.test.ts index 8cc7c004a0f..96d4e404b69 100644 --- a/components/controller/tests/unit/marketplace/marketplace-inventory-resolver-scoping.test.ts +++ b/components/controller/tests/unit/marketplace/marketplace-inventory-resolver-scoping.test.ts @@ -24,10 +24,18 @@ const makeResolver = (ownBranames: string[]) => { const kuChairmanService = { listBranamesForMember: jest.fn().mockResolvedValue(ownBranames), } as any; + // Обогащение результата ФИО заказчиков и реквизитами КУ (см. resolver: + // marketplaceListInventory зовёт их сразу после inventoryRepo.list) — + // тесты скоупинга их содержимое не проверяют, только факт вызова list(). + const orderDisplay = { + resolveAccountNames: jest.fn().mockResolvedValue(new Map()), + enrichByOrderIds: jest.fn().mockResolvedValue(new Map()), + } as any; const resolver = new MarketplaceInventoryResolver( labelService, inventoryRepo, - kuChairmanService + kuChairmanService, + orderDisplay ); return { resolver, inventoryRepo, kuChairmanService }; }; diff --git a/components/controller/tests/unit/marketplace/marketplace-membership-guard.test.ts b/components/controller/tests/unit/marketplace/marketplace-membership-guard.test.ts index 76226b68aa3..27b0c6ffaa8 100644 --- a/components/controller/tests/unit/marketplace/marketplace-membership-guard.test.ts +++ b/components/controller/tests/unit/marketplace/marketplace-membership-guard.test.ts @@ -1,12 +1,13 @@ /** * Unit-тесты MarketplaceMembershipGuard. * - * Story 1.3 (auth/active/server-secret) + Story 3.1 (isOfferer source — whitelist). + * Story 1.3 (auth/active/server-secret) + isOfferer source — реестр поставщиков + * (MarketplaceSupplierRegistryService, заменил whitelist в PR #152). * * Покрывают AC: - * (a) пайщик с user.role='user', status=active, whitelist пуст → guard - * пропускает, marketplace_roles=['orderer','offerer'] (open vitrine); - * (b) пайщик с user.role='user', whitelist непустой и пайщика там нет → + * (a) пайщик с user.role='user', status=active, isOfferer=true → guard + * пропускает, marketplace_roles=['orderer','offerer']; + * (b) пайщик с user.role='user', isOfferer=false → * marketplace_roles=['orderer'] (без offerer); * (c) member и chairman дают расширенный core_roles + marketplace_roles; * (d) status != active → ForbiddenException (HTTP 403); @@ -17,7 +18,7 @@ import { ForbiddenException, UnauthorizedException } from '@nestjs/common'; import { MarketplaceMembershipGuard } from '~/extensions/marketplace/application/guards/marketplace-membership.guard'; import type { MarketplaceKuChairmanService } from '~/extensions/marketplace/application/services/marketplace-ku-chairman.service'; -import type { MarketplaceWhitelistService } from '~/extensions/marketplace/application/services/marketplace-whitelist.service'; +import type { MarketplaceSupplierRegistryService } from '~/extensions/marketplace/application/services/marketplace-supplier-registry.service'; jest.mock('~/config/config', () => ({ __esModule: true, @@ -42,10 +43,10 @@ function makeCtx(req: any) { }; } -function makeWhitelistService(isOffererResult: boolean): MarketplaceWhitelistService { +function makeSupplierRegistryService(isOffererResult: boolean): MarketplaceSupplierRegistryService { return { isOfferer: jest.fn().mockResolvedValue(isOffererResult), - } as unknown as MarketplaceWhitelistService; + } as unknown as MarketplaceSupplierRegistryService; } function makeKuChairmanService(isKuChairmanResult: boolean): MarketplaceKuChairmanService { @@ -55,8 +56,8 @@ function makeKuChairmanService(isKuChairmanResult: boolean): MarketplaceKuChairm } describe('MarketplaceMembershipGuard', () => { - it('user.role=user, status=active, whitelist пуст → ctx [User] + marketplace_roles [orderer, offerer]', async () => { - const guard = new MarketplaceMembershipGuard(makeWhitelistService(true), makeKuChairmanService(false)); + it('user.role=user, status=active, isOfferer=true → ctx [User] + marketplace_roles [orderer, offerer]', async () => { + const guard = new MarketplaceMembershipGuard(makeSupplierRegistryService(true), makeKuChairmanService(false)); const req = { user: { username: 'alice', role: 'user', status: 'active' }, headers: {} }; const ctx = makeCtx(req); @@ -69,8 +70,8 @@ describe('MarketplaceMembershipGuard', () => { expect(req).toHaveProperty('currentMember'); }); - it('user.role=user, whitelist непустой и пайщика там нет → marketplace_roles [orderer] (без offerer)', async () => { - const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmanService(false)); + it('user.role=user, isOfferer=false → marketplace_roles [orderer] (без offerer)', async () => { + const guard = new MarketplaceMembershipGuard(makeSupplierRegistryService(false), makeKuChairmanService(false)); const req = { user: { username: 'alice', role: 'user', status: 'active' }, headers: {} }; const ctx = makeCtx(req); @@ -79,7 +80,7 @@ describe('MarketplaceMembershipGuard', () => { }); it('user.role=member, status=active → core_roles [User, Member] + marketplace_roles [orderer, offerer, board_readonly]', async () => { - const guard = new MarketplaceMembershipGuard(makeWhitelistService(true), makeKuChairmanService(false)); + const guard = new MarketplaceMembershipGuard(makeSupplierRegistryService(true), makeKuChairmanService(false)); const req = { user: { username: 'bob', role: 'member', status: 'active' }, headers: {} }; const ctx = makeCtx(req); await expect(guard.canActivate(ctx as any)).resolves.toBe(true); @@ -92,7 +93,7 @@ describe('MarketplaceMembershipGuard', () => { }); it('user.role=chairman, status=active → marketplace_roles полный набор', async () => { - const guard = new MarketplaceMembershipGuard(makeWhitelistService(true), makeKuChairmanService(false)); + const guard = new MarketplaceMembershipGuard(makeSupplierRegistryService(true), makeKuChairmanService(false)); const req = { user: { username: 'chair', role: 'chairman', status: 'active' }, headers: {} }; const ctx = makeCtx(req); await expect(guard.canActivate(ctx as any)).resolves.toBe(true); @@ -107,7 +108,7 @@ describe('MarketplaceMembershipGuard', () => { }); it('status != active → 403 Forbidden «Доступ только для пайщиков кооператива»', async () => { - const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmanService(false)); + const guard = new MarketplaceMembershipGuard(makeSupplierRegistryService(false), makeKuChairmanService(false)); const req = { user: { username: 'alice', role: 'user', status: '4_Registered' }, headers: {} }; const ctx = makeCtx(req); await expect(guard.canActivate(ctx as any)).rejects.toThrow(ForbiddenException); @@ -117,14 +118,14 @@ describe('MarketplaceMembershipGuard', () => { }); it('нет user (нет JWT) → 401 Unauthorized', async () => { - const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmanService(false)); + const guard = new MarketplaceMembershipGuard(makeSupplierRegistryService(false), makeKuChairmanService(false)); const req = { headers: {} }; const ctx = makeCtx(req); await expect(guard.canActivate(ctx as any)).rejects.toThrow(UnauthorizedException); }); - it('server-secret bypass → true, currentMember не выставляется, whitelist/branches не дёргаются', async () => { - const ws = makeWhitelistService(true); + it('server-secret bypass → true, currentMember не выставляется, supplierRegistry/kuChairman не дёргаются', async () => { + const ws = makeSupplierRegistryService(true); const ku = makeKuChairmanService(false); const guard = new MarketplaceMembershipGuard(ws, ku); const req = { headers: { 'server-secret': 'test-secret' } }; @@ -136,7 +137,7 @@ describe('MarketplaceMembershipGuard', () => { }); it('isKuChairman=true → marketplace_roles содержит operator', async () => { - const guard = new MarketplaceMembershipGuard(makeWhitelistService(false), makeKuChairmanService(true)); + const guard = new MarketplaceMembershipGuard(makeSupplierRegistryService(false), makeKuChairmanService(true)); const req = { user: { username: 'chairkrg', role: 'user', status: 'active' }, headers: {} }; const ctx = makeCtx(req); await expect(guard.canActivate(ctx as any)).resolves.toBe(true); diff --git a/components/controller/tests/unit/marketplace/marketplace-moderation-service.test.ts b/components/controller/tests/unit/marketplace/marketplace-moderation-service.test.ts index a3499bf1b38..b695e78d0a8 100644 --- a/components/controller/tests/unit/marketplace/marketplace-moderation-service.test.ts +++ b/components/controller/tests/unit/marketplace/marketplace-moderation-service.test.ts @@ -43,6 +43,8 @@ function makeOffer(overrides: Partial = {}): Marke warranty_days: 0, barcode_strategy: 'PER_ORDER', pack_size: null, + stock_braname: null, + stock_origin_offer_id: null, images: [], status: 'PENDING_MODERATION', approved_by: null, diff --git a/components/controller/tests/unit/marketplace/marketplace-offer-counters-service.test.ts b/components/controller/tests/unit/marketplace/marketplace-offer-counters-service.test.ts index 896bca41cc8..37ca2fc0a96 100644 --- a/components/controller/tests/unit/marketplace/marketplace-offer-counters-service.test.ts +++ b/components/controller/tests/unit/marketplace/marketplace-offer-counters-service.test.ts @@ -43,6 +43,8 @@ function makeOffer(overrides: Partial = {}): Marke warranty_days: 0, barcode_strategy: 'PER_ORDER', pack_size: null, + stock_braname: null, + stock_origin_offer_id: null, images: [], status: 'ACTIVE', approved_by: 'chair', diff --git a/components/controller/tests/unit/marketplace/marketplace-whitelist-service.test.ts b/components/controller/tests/unit/marketplace/marketplace-whitelist-service.test.ts deleted file mode 100644 index 7750df46e7d..00000000000 --- a/components/controller/tests/unit/marketplace/marketplace-whitelist-service.test.ts +++ /dev/null @@ -1,161 +0,0 @@ -/** - * Unit-тесты MarketplaceWhitelistService (Story 3.1). - * - * Покрывают AC: - * - listWhitelist возвращает все записи (auto-coop + manual); - * - addToWhitelist создаёт role='manual', проставляет added_by; - * - removeFromWhitelist удаляет manual-запись и инвалидирует кеш; - * - removeFromWhitelist на auto-coop → 403 Forbidden (FR5); - * - removeFromWhitelist на отсутствующего → 404 NotFound; - * - isOfferer семантика «открытая витрина» (whitelist только auto-coop) - * → true для всех; - * - isOfferer семантика «по whitelist» → true только для записанных; - * - isOfferer cache hit без обращения к репозиторию. - */ -import { ForbiddenException, NotFoundException } from '@nestjs/common'; - -import { MarketplaceWhitelistService } from '~/extensions/marketplace/application/services/marketplace-whitelist.service'; -import { MarketplaceWhitelistEntryDomainEntity } from '~/extensions/marketplace/domain/entities/marketplace-whitelist-entry.entity'; -import type { MarketplaceWhitelistDomainRepository } from '~/extensions/marketplace/domain/repositories/marketplace-whitelist.repository'; - -const COOP = 'voskhod'; - -function makeEntry(member: string, role: 'auto-coop' | 'manual'): MarketplaceWhitelistEntryDomainEntity { - return new MarketplaceWhitelistEntryDomainEntity({ - id: `id-${member}`, - coopname: COOP, - member_account: member, - role, - added_by: role === 'auto-coop' ? null : 'admin', - added_at: new Date('2026-05-15T12:00:00Z'), - }); -} - -function makeRepo(): jest.Mocked { - return { - list: jest.fn(), - findByMember: jest.fn(), - add: jest.fn(), - remove: jest.fn(), - countManual: jest.fn(), - }; -} - -describe('MarketplaceWhitelistService', () => { - it('list возвращает все записи', async () => { - const repo = makeRepo(); - repo.list.mockResolvedValue([makeEntry(COOP, 'auto-coop'), makeEntry('alice', 'manual')]); - const service = new MarketplaceWhitelistService(repo); - - const result = await service.list(COOP); - expect(result).toHaveLength(2); - expect(result.map((e) => e.member_account)).toEqual([COOP, 'alice']); - }); - - it('addToWhitelist создаёт manual-запись с added_by', async () => { - const repo = makeRepo(); - repo.add.mockResolvedValue(makeEntry('bob', 'manual')); - const service = new MarketplaceWhitelistService(repo); - - const entry = await service.addToWhitelist(COOP, 'bob', 'admin'); - expect(entry.member_account).toBe('bob'); - expect(entry.role).toBe('manual'); - expect(repo.add).toHaveBeenCalledWith(COOP, 'bob', 'manual', 'admin'); - }); - - it('removeFromWhitelist удаляет manual-запись', async () => { - const repo = makeRepo(); - repo.findByMember.mockResolvedValue(makeEntry('bob', 'manual')); - const service = new MarketplaceWhitelistService(repo); - - await service.removeFromWhitelist(COOP, 'bob'); - expect(repo.remove).toHaveBeenCalledWith(COOP, 'bob'); - }); - - it('removeFromWhitelist на auto-coop → 403 (FR5)', async () => { - const repo = makeRepo(); - repo.findByMember.mockResolvedValue(makeEntry(COOP, 'auto-coop')); - const service = new MarketplaceWhitelistService(repo); - - await expect(service.removeFromWhitelist(COOP, COOP)).rejects.toThrow(ForbiddenException); - expect(repo.remove).not.toHaveBeenCalled(); - }); - - it('removeFromWhitelist на отсутствующего → 404 NotFound', async () => { - const repo = makeRepo(); - repo.findByMember.mockResolvedValue(null); - const service = new MarketplaceWhitelistService(repo); - - await expect(service.removeFromWhitelist(COOP, 'ghost')).rejects.toThrow(NotFoundException); - }); - - it('isOfferer: открытая витрина (только auto-coop) → true для всех', async () => { - const repo = makeRepo(); - repo.countManual.mockResolvedValue(0); - const service = new MarketplaceWhitelistService(repo); - - await expect(service.isOfferer(COOP, 'random_user')).resolves.toBe(true); - expect(repo.findByMember).not.toHaveBeenCalled(); - }); - - it('isOfferer: whitelist непустой, пайщик внутри → true', async () => { - const repo = makeRepo(); - repo.countManual.mockResolvedValue(2); - repo.findByMember.mockResolvedValue(makeEntry('alice', 'manual')); - const service = new MarketplaceWhitelistService(repo); - - await expect(service.isOfferer(COOP, 'alice')).resolves.toBe(true); - }); - - it('isOfferer: whitelist непустой, пайщик снаружи → false', async () => { - const repo = makeRepo(); - repo.countManual.mockResolvedValue(2); - repo.findByMember.mockResolvedValue(null); - const service = new MarketplaceWhitelistService(repo); - - await expect(service.isOfferer(COOP, 'random_user')).resolves.toBe(false); - }); - - it('isOfferer: второй вызов того же пайщика — cache hit, repo не дёргается', async () => { - const repo = makeRepo(); - repo.countManual.mockResolvedValue(0); - const service = new MarketplaceWhitelistService(repo); - - await service.isOfferer(COOP, 'alice'); - await service.isOfferer(COOP, 'alice'); - expect(repo.countManual).toHaveBeenCalledTimes(1); - }); - - it('addToWhitelist инвалидирует кеш isOfferer', async () => { - const repo = makeRepo(); - repo.countManual.mockResolvedValueOnce(0); - repo.add.mockResolvedValue(makeEntry('alice', 'manual')); - repo.countManual.mockResolvedValueOnce(1); - repo.findByMember.mockResolvedValue(null); - const service = new MarketplaceWhitelistService(repo); - - // Прогрев кеша: открытая витрина → true - await expect(service.isOfferer(COOP, 'random_user')).resolves.toBe(true); - // Добавление manual-записи (alice) → инвалидирует кеш - await service.addToWhitelist(COOP, 'alice', 'admin'); - // После инвалидации семантика «по whitelist» → false для random_user - await expect(service.isOfferer(COOP, 'random_user')).resolves.toBe(false); - }); - - it('removeFromWhitelist инвалидирует кеш isOfferer', async () => { - const repo = makeRepo(); - // Прогрев isOfferer: countManual=1 + findByMember(random_user)=null → false. - // Затем remove('alice'): findByMember(alice)=manual-entry, repo.remove() ok. - // Второй isOfferer: countManual=0 → семантика «открытая витрина» → true, - // findByMember не дёргается (короткое замыкание). - repo.countManual.mockResolvedValueOnce(1).mockResolvedValueOnce(0); - repo.findByMember - .mockResolvedValueOnce(null) - .mockResolvedValueOnce(makeEntry('alice', 'manual')); - const service = new MarketplaceWhitelistService(repo); - - await expect(service.isOfferer(COOP, 'random_user')).resolves.toBe(false); - await service.removeFromWhitelist(COOP, 'alice'); - await expect(service.isOfferer(COOP, 'random_user')).resolves.toBe(true); - }); -}); -- 2.52.0 From d7f88b661f5bbdd3ae161fbf1c30cc11a68e032a Mon Sep 17 00:00:00 2001 From: ant Date: Tue, 21 Jul 2026 08:44:52 +0000 Subject: [PATCH 3/3] =?UTF-8?q?[598-51][@ant]=20fix:=20=D0=BF=D0=BE=D0=BA?= =?UTF-8?q?=D0=B0=D0=B7=D0=B0=D1=82=D1=8C=20=D0=B7=D0=B0=D0=BA=D0=B0=D0=B7?= =?UTF-8?q?=D1=87=D0=B8=D0=BA=D1=83=20=D0=B8=20=D0=BF=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=B2=D1=89=D0=B8=D0=BA=D1=83=20=D0=BA=D0=BE=D1=80=D1=80?= =?UTF-8?q?=D0=B5=D0=BA=D1=82=D0=BD=D1=83=D1=8E=20=D1=81=D1=83=D0=BC=D0=BC?= =?UTF-8?q?=D1=83=20=D1=81=20=D1=87=D0=BB=D0=B5=D0=BD=D1=81=D0=BA=D0=B8?= =?UTF-8?q?=D0=BC=20=D0=B2=D0=B7=D0=BD=D0=BE=D1=81=D0=BE=D0=BC=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B2=D1=81=D0=B5=D1=85=20=D1=8D=D0=BA=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=D0=B0=D1=85=20=D0=A1=D1=82=D0=BE=D0=BB=D0=B0=20=D0=B7?= =?UTF-8?q?=D0=B0=D0=BA=D0=B0=D0=B7=D0=BE=D0=B2,=20=D0=B4=D0=BE=D0=B1?= =?UTF-8?q?=D0=B8=D1=82=D1=8C=20=D1=82=D0=BE=D1=87=D0=B5=D1=87=D0=BD=D1=8B?= =?UTF-8?q?=D0=B5=20UI-=D0=B1=D0=B0=D0=B3=D0=B8=20=D0=B8=20TS-=D0=BE=D1=88?= =?UTF-8?q?=D0=B8=D0=B1=D0=BA=D0=B8=20=E2=80=94=20=D1=80=D0=B5=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D1=80=20=D0=BF=D0=BE=D1=81=D1=82=D0=B0=D0=B2=D1=89=D0=B8?= =?UTF-8?q?=D0=BA=D0=BE=D0=B2=20=D0=B8=20=D0=BF=D1=83=D0=BD=D0=BA=D1=82?= =?UTF-8?q?=D1=8B=20=D0=B2=D1=8B=D0=B4=D0=B0=D1=87=D0=B8=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D1=83=D1=87=D0=B8=D0=BB=D0=B8=20=D0=A4=D0=98=D0=9E/?= =?UTF-8?q?=D0=BD=D0=B0=D0=B8=D0=BC=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20=D0=B3?= =?UTF-8?q?=D0=BE=D0=BB=D0=BE=D0=B3=D0=BE=20username,=20=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D0=BB=20=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D0=B8=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D1=80=D0=B0=20=D0=B8=20=D0=BE=D0=BD=D0=B1?= =?UTF-8?q?=D0=BE=D1=80=D0=B4=D0=B8=D0=BD=D0=B3=20=D0=BF=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B0=D0=B2=D1=89=D0=B8=D0=BA=D0=B0=20=D0=BF=D0=BE=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=BF=D0=BE=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D1=88=D0=BB=D1=8B=D0=BC=20=D0=B7=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=87=D0=B0=D0=BD=D0=B8=D1=8F=D0=BC,=20=D0=B4=D0=BE=D0=BA?= =?UTF-8?q?=D0=BB=D0=B0=D0=B4=D0=BA=D0=B0=20=D1=83=20=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D0=B9=D0=BA=D0=B8=20=D0=B2=D1=8B=D0=B4=D0=B0=D1=87=D0=B8=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=BF=D1=83=D1=81=D0=BA=D0=B0=D0=BB=D0=B0=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=8F=D0=B7=D0=B0=D1=82=D0=B5=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D1=83=D1=8E=20=D0=BF=D0=BE=D0=B4=D0=BF=D0=B8=D1=81=D1=8C=20?= =?UTF-8?q?=D0=BE=D0=BF=D0=B5=D1=80=D0=B0=D1=82=D0=BE=D1=80=D0=B0=20=D0=B8?= =?UTF-8?q?=20=D0=BF=D0=B0=D0=B4=D0=B0=D0=BB=D0=B0=20=D0=B1=D1=8B=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=B1=D1=8D=D0=BA=D0=B5,=20=D0=BF=D0=BB=D1=8E=D1=81?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=BA=D1=80=D1=8B=D1=82=D1=8B=20=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D0=B2=D1=88=D0=B8=D0=B5=D1=81=D1=8F=20unknown/null?= =?UTF-8?q?able=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BF=D0=B8=D0=BB=D1=8F=D1=86=D0=B8=D0=B8=20desktop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5 --- .../desktop/extensions/market/install.ts | 2 +- .../pages/PostingsPage/ui/PostingsPage.vue | 2 +- .../desktop/src-ssr/middlewares/injectEnv.ts | 1 + components/desktop/src/boot/index.ts | 1 - .../ui/AdminIssuancePointsPage.vue | 22 +++++------- .../AdminOrders/ui/AdminOrdersPage.vue | 9 +++-- .../pages/Marketplace/Cart/ui/CartPage.vue | 14 ++++---- .../MarketplaceCatalog/ui/AddToCartDialog.vue | 27 +++++++++++---- .../ui/MarketplaceCatalogPage.vue | 3 +- .../MarketplaceOfferDetail/api/index.ts | 2 +- .../ui/MarketplaceOfferDetailPage.vue | 26 ++++++++++++-- .../Marketplace/MyOrders/ui/MyOrdersPage.vue | 6 ++-- .../ui/OffererIncomingOrdersPage.vue | 7 +++- .../OffererSupplyPreparation/lib/ttn.ts | 2 +- .../ui/OnboardingMemberPickCppPage.vue | 4 +-- .../ui/OperatorBranchEconomyPage.vue | 2 +- .../ui/OperatorReceptionPage.vue | 4 +-- .../ui/OrdererConsolidatedPage.vue | 3 +- .../ui/OrdererOrderDetailPage.vue | 14 ++++++-- .../ui/SupplierRegistryPage.vue | 3 +- .../Registrator/SignUp/SelectProgram.vue | 2 +- .../desktop/src/shared/config/Environment.ts | 1 + .../src/shared/config/createEnvObject.ts | 1 + .../src/shared/lib/marketplace/index.ts | 1 + .../shared/lib/marketplace/membership-fee.ts | 11 ++++-- .../lib/marketplace/reception-grouping.ts | 4 +-- .../src/shared/ui/Providers/Bank/Bank.vue | 2 +- .../shared/ui/base/BaseInput/BaseInput.vue | 6 ++-- .../CatalogOfferCard/CatalogOfferCard.vue | 3 +- .../model/useOnsiteSignatureGate.ts | 28 +++++++++------ .../Marketplace/OrderCard/OrderCard.vue | 14 ++++++++ .../OrderCard/lib/toOrderCardModel.ts | 22 ++++++++++-- .../StockRestockPanel/StockRestockPanel.vue | 34 +++++++++++++++++-- .../SupplyPartyCard/SupplyPartyCard.vue | 12 +++++++ .../ProcessDetailCard/ProcessDetailCard.vue | 3 +- 35 files changed, 219 insertions(+), 79 deletions(-) diff --git a/components/desktop/extensions/market/install.ts b/components/desktop/extensions/market/install.ts index 48b2d03c912..2d05133975b 100644 --- a/components/desktop/extensions/market/install.ts +++ b/components/desktop/extensions/market/install.ts @@ -708,7 +708,7 @@ export default async function (): Promise { component: markRaw(AdminOffersPage), meta: { title: 'Реестр предложений', - icon: 'storefront', + icon: 'sell', requires: 'Offer:read:all', requiresAuth: true, agreements: agreementsBase, diff --git a/components/desktop/extensions/reports/pages/PostingsPage/ui/PostingsPage.vue b/components/desktop/extensions/reports/pages/PostingsPage/ui/PostingsPage.vue index e680c8625bc..c315b80efce 100644 --- a/components/desktop/extensions/reports/pages/PostingsPage/ui/PostingsPage.vue +++ b/components/desktop/extensions/reports/pages/PostingsPage/ui/PostingsPage.vue @@ -209,7 +209,7 @@ EntityIdBadge( v-if='props.row.processHash' :rawId='shortHash(props.row.processHash)' - @click='copyFullHash(props.row.processHash)' + @click='copyText(props.row.processHash)' ) diff --git a/components/desktop/src-ssr/middlewares/injectEnv.ts b/components/desktop/src-ssr/middlewares/injectEnv.ts index 461a00e3fb2..8d3629bc61c 100644 --- a/components/desktop/src-ssr/middlewares/injectEnv.ts +++ b/components/desktop/src-ssr/middlewares/injectEnv.ts @@ -26,6 +26,7 @@ export default ssrMiddleware(({ app }) => { VAPID_PUBLIC_KEY: process.env.VAPID_PUBLIC_KEY as string, SENTRY_DSN: process.env.SENTRY_DSN as string, OPENREPLAY_PROJECT_KEY: process.env.OPENREPLAY_PROJECT_KEY as string, + YANDEX_MAPS_API_KEY: process.env.YANDEX_MAPS_API_KEY as string, }; // Создаем скрипт, который добавит переменные в window.__ENV__ diff --git a/components/desktop/src/boot/index.ts b/components/desktop/src/boot/index.ts index 0766154b410..1b804666a23 100644 --- a/components/desktop/src/boot/index.ts +++ b/components/desktop/src/boot/index.ts @@ -1,5 +1,4 @@ export { default as init } from './init'; export { default as axios } from './axios'; export { default as sentry } from './sentry'; -export { default as map } from './map'; export { default as chatwoot } from './chatwoot'; diff --git a/components/desktop/src/pages/Marketplace/AdminIssuancePoints/ui/AdminIssuancePointsPage.vue b/components/desktop/src/pages/Marketplace/AdminIssuancePoints/ui/AdminIssuancePointsPage.vue index b03149abeb3..2ff65758ddf 100644 --- a/components/desktop/src/pages/Marketplace/AdminIssuancePoints/ui/AdminIssuancePointsPage.vue +++ b/components/desktop/src/pages/Marketplace/AdminIssuancePoints/ui/AdminIssuancePointsPage.vue @@ -14,7 +14,7 @@ import { GeocodeStatus, KuDetailsStatus } from 'src/entities/MarketplaceKUDetail import type { IMarketplaceKUDetails } from 'src/entities/MarketplaceKUDetails' import { BaseBadge, BaseButton, BaseDialog, EmptyState, TableSkeleton } from 'src/shared/ui/base' import type { BaseBadgeVariant, TableSkeletonColumn } from 'src/shared/ui/base' -import { PageHint } from 'src/shared/ui/domain' +import { IdentityCell, PageHint } from 'src/shared/ui/domain' import { useMarketplaceRealtime } from 'src/shared/lib/marketplace' // Map экспортируется как `Map` — импортируем под алиасом, чтобы не затенять // глобальный `Map` (используется в `rows`). @@ -81,6 +81,10 @@ function statusOf(row: IssuancePointRow): { label: string; variant: BaseBadgeVar return STATUS_LABEL[row.details.status] } +function branchName(row: IssuancePointRow): string { + return row.branch.short_name || row.branch.full_name || '' +} + function addressOf(row: IssuancePointRow): string { return ( row.details?.addressFull || @@ -213,8 +217,10 @@ q-page.admin-pvz tbody tr(v-for='row in rows', :key='row.branch.braname') td.col-ku - .admin-pvz__ku-name {{ row.branch.short_name || row.branch.full_name || row.branch.braname }} - .admin-pvz__ku-acc {{ row.branch.braname }} + IdentityCell( + :account-name='row.branch.braname', + :full-name='branchName(row)' + ) td.col-city {{ row.branch.city || '—' }} td.admin-pvz__address {{ addressOf(row) }} td.col-status @@ -334,16 +340,6 @@ q-page.admin-pvz font-size: 0.875rem; } - &__ku-name { - font-weight: 600; - } - - &__ku-acc { - font-family: var(--font-mono); - font-size: 0.8125rem; - color: var(--p-ink-3); - } - &__address { color: var(--p-ink-2); } diff --git a/components/desktop/src/pages/Marketplace/AdminOrders/ui/AdminOrdersPage.vue b/components/desktop/src/pages/Marketplace/AdminOrders/ui/AdminOrdersPage.vue index 0c57285f42d..f0c8e5069a0 100644 --- a/components/desktop/src/pages/Marketplace/AdminOrders/ui/AdminOrdersPage.vue +++ b/components/desktop/src/pages/Marketplace/AdminOrders/ui/AdminOrdersPage.vue @@ -90,8 +90,11 @@ function shortId(id: string | null | undefined): string { function unitLabel(o: AdminOrderView): string { return marketplaceUnitShort(o.unit_of_measure); } -function formatTotal(v: string | null | undefined): string { - return v ? formatAsset2Digits(String(v)) : '—'; +// requirement b6: реестр показывает сумму, которую реально заплатил пайщик +// (себестоимость + членский взнос, зафиксированный в заказе контрактом) — +// не голую себестоимость товара. +function formatTotalWithFee(o: AdminOrderView): string { + return formatAsset2Digits(o.total_cost_with_fee); } function formatDate(d: unknown): string { if (d === null || d === undefined) return '—'; @@ -255,7 +258,7 @@ q-page.admin-orders(role="region", aria-label="Реестр заказов ко q-td {{ ordererTitle(props.row) }} q-td {{ supplierTitle(props.row) }} q-td.text-right {{ props.row.quantity }} {{ unitLabel(props.row) }} - q-td.text-right.font-monospace {{ formatTotal(props.row.total_cost) }} + q-td.text-right.font-monospace {{ formatTotalWithFee(props.row) }} q-td {{ formatDate(props.row.created_at) }} q-tr.q-virtual-scroll--with-prev( diff --git a/components/desktop/src/pages/Marketplace/Cart/ui/CartPage.vue b/components/desktop/src/pages/Marketplace/Cart/ui/CartPage.vue index 3f41365e492..670deae726f 100644 --- a/components/desktop/src/pages/Marketplace/Cart/ui/CartPage.vue +++ b/components/desktop/src/pages/Marketplace/Cart/ui/CartPage.vue @@ -11,7 +11,7 @@ import { import { BaseCard, BaseButton, BaseChip, EmptyState } from 'src/shared/ui/base'; import { KUHeaderBar } from 'src/widgets/Marketplace/KUHeaderBar'; import { marketplaceUnitShort } from 'src/shared/lib/consts'; -import { useMarketplaceRealtime, getMembershipFeePercent } from 'src/shared/lib/marketplace'; +import { useMarketplaceRealtime, getMembershipFeePercent, applyMembershipFee } from 'src/shared/lib/marketplace'; /** * Эпик 16 / Story 16.1 + 16.2: страница корзины заказчика и оформление. @@ -35,12 +35,12 @@ const coopname = computed(() => String(route.params.coopname ?? '')); const symbol = computed(() => system.governSymbol); -function unitShort(u: string): string { - return marketplaceUnitShort(u as Parameters[0]); +function unitShort(u: string | null | undefined): string { + return marketplaceUnitShort((u ?? '') as Parameters[0]); } -function money(value: string | number): string { - return Number(value).toLocaleString('ru-RU'); +function money(value: string | number | null | undefined): string { + return Number(value ?? 0).toLocaleString('ru-RU'); } // Низкоуровневый коммит количества (целое ≥ 1). Кламп делает changeQty. @@ -156,8 +156,8 @@ useMarketplaceRealtime( // requirement b6: членский взнос входит в общую стоимость заказа — сводка // показывает его отдельной строкой и итог с учётом взноса. const feePercent = ref(0); -const feeAmount = computed(() => (cartStore.totalCost * feePercent.value) / 100); -const totalWithFee = computed(() => cartStore.totalCost + feeAmount.value); +const totalWithFee = computed(() => applyMembershipFee(Number(cartStore.totalCost), feePercent.value)); +const feeAmount = computed(() => totalWithFee.value - Number(cartStore.totalCost)); onMounted(async () => { try { diff --git a/components/desktop/src/pages/Marketplace/MarketplaceCatalog/ui/AddToCartDialog.vue b/components/desktop/src/pages/Marketplace/MarketplaceCatalog/ui/AddToCartDialog.vue index 00c1f2af8b5..8aae6f1c855 100644 --- a/components/desktop/src/pages/Marketplace/MarketplaceCatalog/ui/AddToCartDialog.vue +++ b/components/desktop/src/pages/Marketplace/MarketplaceCatalog/ui/AddToCartDialog.vue @@ -4,6 +4,7 @@ import { useRoute, useRouter } from 'vue-router'; import { FailAlert, SuccessAlert } from 'src/shared/api'; import { useSystemStore } from 'src/entities/System/model'; import { useMarketplaceCartStore } from 'src/entities/MarketplaceCart'; +import { applyMembershipFee } from 'src/shared/lib/marketplace'; import { BaseDialog, BaseInput, BaseButton } from 'src/shared/ui/base'; import type { MarketplaceOfferView } from '../types'; @@ -29,10 +30,16 @@ const cartStore = useMarketplaceCartStore(); const router = useRouter(); const route = useRoute(); -const props = defineProps<{ - modelValue: boolean; - offer: CartOffer | null; -}>(); +const props = withDefaults( + defineProps<{ + modelValue: boolean; + offer: CartOffer | null; + // Единая ставка членского взноса кооператива, проценты (requirement b6). + // Цена и итог показываются заказчику с учётом взноса — как в каталоге. + feePercent?: number; + }>(), + { feePercent: 0 }, +); const emit = defineEmits<{ (e: 'update:modelValue', value: boolean): void; @@ -64,10 +71,14 @@ const maxQuantity = computed(() => { return props.offer.quantity_available; }); -const totalSum = computed(() => { +const priceWithFee = computed(() => { if (!props.offer) return 0; + return applyMembershipFee(Number(props.offer.price_per_unit), props.feePercent); +}); + +const totalSum = computed(() => { const q = Number(quantity.value) || 0; - return q * Number(props.offer.price_per_unit); + return q * priceWithFee.value; }); // Сколько этой позиции уже в корзине — подсказка, чтобы заказчик не дублировал. @@ -148,7 +159,9 @@ BaseDialog( .add-to-cart__note(v-if="alreadyInCart > 0") | Уже в корзине: {{ alreadyInCart }} {{ unitLabel }} — добавление суммируется. .add-to-cart__price(v-if="offer") - | Цена: {{ Number(offer.price_per_unit).toLocaleString('ru-RU') }} {{ system.governSymbol }} за {{ unitLabel }} + | Цена: {{ priceWithFee.toLocaleString('ru-RU') }} {{ system.governSymbol }} за {{ unitLabel }} + template(v-if="feePercent > 0") + | (с членским взносом {{ feePercent }}%) .add-to-cart__total(v-if="offer") | Итого: {{ totalSum.toLocaleString('ru-RU') }} {{ system.governSymbol }} template(#footer) diff --git a/components/desktop/src/pages/Marketplace/MarketplaceCatalog/ui/MarketplaceCatalogPage.vue b/components/desktop/src/pages/Marketplace/MarketplaceCatalog/ui/MarketplaceCatalogPage.vue index 540b028a161..e780517d7f4 100644 --- a/components/desktop/src/pages/Marketplace/MarketplaceCatalog/ui/MarketplaceCatalogPage.vue +++ b/components/desktop/src/pages/Marketplace/MarketplaceCatalog/ui/MarketplaceCatalogPage.vue @@ -410,7 +410,8 @@ q-page.catalog(role="region", aria-label="Каталог Стола заказо AddToCartDialog( v-model="cartDialogOpen", - :offer="cartDialogOffer" + :offer="cartDialogOffer", + :fee-percent="feePercent" ) diff --git a/components/desktop/src/pages/Marketplace/MarketplaceOfferDetail/api/index.ts b/components/desktop/src/pages/Marketplace/MarketplaceOfferDetail/api/index.ts index f9a15fa4688..13c15441274 100644 --- a/components/desktop/src/pages/Marketplace/MarketplaceOfferDetail/api/index.ts +++ b/components/desktop/src/pages/Marketplace/MarketplaceOfferDetail/api/index.ts @@ -12,5 +12,5 @@ export async function fetchOffer(id: string): Promise { : `В наличии: ${offer.value.quantity_available} ${unitShort.value}`; }); +// requirement b6: единая ставка членского взноса входит в цену, которую видит +// заказчик — как в карточке каталога (CatalogOfferCard). Раздельная +// себестоимость без взноса остаётся только на столе поставщика. +const feePercent = ref(0); +const priceWithFee = computed(() => + offer.value ? applyMembershipFee(Number(offer.value.price_per_unit), feePercent.value) : 0, +); const priceLabel = computed(() => offer.value - ? `${Number(offer.value.price_per_unit).toLocaleString('ru-RU')} ${system.governSymbol} / ${unitShort.value}` + ? `${priceWithFee.value.toLocaleString('ru-RU')} ${system.governSymbol} / ${unitShort.value}` : '', ); @@ -157,6 +164,11 @@ useMarketplaceRealtime( ); onMounted(async () => { + try { + feePercent.value = await getMembershipFeePercent(); + } catch { + // Без ставки показываем цену без строки взноса. + } await load(); // В режиме заказа нужен текущий КУ (для кнопки «В корзину» и диалога). if (!readonly.value) { @@ -209,6 +221,7 @@ q-page.offer-detail(role="region", aria-label="Описание предложе span {{ offer.supplier_name }} .offer-detail__price {{ priceLabel }} + .offer-detail__fee-note(v-if="feePercent > 0") Цена с членским взносом {{ feePercent }}% BaseButton( v-if="!readonly", @@ -257,7 +270,8 @@ q-page.offer-detail(role="region", aria-label="Описание предложе AddToCartDialog( v-if="!readonly", v-model="cartDialogOpen", - :offer="offer" + :offer="offer", + :fee-percent="feePercent" ) @@ -333,6 +347,12 @@ q-page.offer-detail(role="region", aria-label="Описание предложе color: var(--p-primary-strong); } + &__fee-note { + font-size: var(--p-fs-body-sm); + color: var(--p-ink-3); + margin-top: calc(var(--p-1, 4px) * -1); + } + &__sections { display: flex; flex-direction: column; diff --git a/components/desktop/src/pages/Marketplace/MyOrders/ui/MyOrdersPage.vue b/components/desktop/src/pages/Marketplace/MyOrders/ui/MyOrdersPage.vue index b01b91e6aba..86034570f13 100644 --- a/components/desktop/src/pages/Marketplace/MyOrders/ui/MyOrdersPage.vue +++ b/components/desktop/src/pages/Marketplace/MyOrders/ui/MyOrdersPage.vue @@ -143,13 +143,13 @@ function groupByCheckout(list: MarketplaceOrderView[]): OrderGroup[] { } const result: OrderGroup[] = Array.from(map.entries()).map(([key, orders]) => { const first = orders[0]; - const recent = Math.max(...orders.map((o) => new Date(o.updated_at).getTime())); + const recent = Math.max(...orders.map((o) => new Date(String(o.updated_at)).getTime())); return { key, isAggregate: orders.length > 1, orders, count: orders.length, - totalCost: orders.reduce((s, o) => s + Number(o.total_cost), 0), + totalCost: orders.reduce((s, o) => s + Number(o.total_cost_with_fee), 0), deliveryName: first?.delivery_point_name || first?.delivery_braname || '', createdAt: first?.created_at ?? '', recent, @@ -250,7 +250,7 @@ async function onLoadMore(): Promise { function confirmCancel(order: MarketplaceOrderView): void { Dialog.create({ title: 'Отменить заказ?', - message: `Заказ № ${order.id.slice(0, 8)} (${order.quantity} ед., ${order.total_cost} ₽) будет отменён. Средства разблокируются на кошельке Стола заказов.`, + message: `Заказ № ${order.id.slice(0, 8)} (${order.quantity} ед., ${money(order.total_cost_with_fee)} ₽) будет отменён. Средства разблокируются на кошельке Стола заказов.`, cancel: { label: 'Не отменять', flat: true }, ok: { label: 'Отменить заказ', color: 'negative', unelevated: true }, persistent: true, diff --git a/components/desktop/src/pages/Marketplace/OffererIncomingOrders/ui/OffererIncomingOrdersPage.vue b/components/desktop/src/pages/Marketplace/OffererIncomingOrders/ui/OffererIncomingOrdersPage.vue index 7762cc1c980..ce1d69090f5 100644 --- a/components/desktop/src/pages/Marketplace/OffererIncomingOrders/ui/OffererIncomingOrdersPage.vue +++ b/components/desktop/src/pages/Marketplace/OffererIncomingOrders/ui/OffererIncomingOrdersPage.vue @@ -122,6 +122,8 @@ interface SupplierParty { orders: MarketplaceOrderView[]; totalUnits: number; totalCost: number; + /** Сумма членских взносов пайщиков по заказам партии (requirement b6) — справочно, не деньги поставщика. */ + totalFee: number; /** Целевой минимальный объём поставки на этот КУ (для накопителя). */ minVolume: number | null; stageStatus: MarketplaceOrderStatusView; @@ -150,6 +152,7 @@ const parties = computed(() => { orders: [], totalUnits: 0, totalCost: 0, + totalFee: 0, minVolume: collecting ? (minVolumeMap.value.get(`${o.offer_id}::${o.delivery_braname}`) ?? null) : null, @@ -160,6 +163,7 @@ const parties = computed(() => { p.orders.push(o); p.totalUnits += o.quantity; p.totalCost += parseFloat(o.total_cost) || 0; + p.totalFee += Number(o.membership_fee ?? 0) || 0; const candidate = STAGE_RANK[o.status]; const current = STAGE_RANK[p.stageStatus]; if (candidate < 90 && (current >= 90 || candidate < current)) { @@ -340,7 +344,8 @@ q-page.incoming-orders(role='region', aria-label='Входящие заказы :bar-color='barColor(p)', :members='[]', total-label='Итого', - :total-value='`${formatCost(p.totalCost)} · ${p.totalUnits} ${p.unitLabel}`' + :total-value='`${formatCost(p.totalCost)} · ${p.totalUnits} ${p.unitLabel}`', + :total-fee-note='p.totalFee > 0 ? `С учётом взноса пайщиков: ${formatCost(p.totalCost + p.totalFee)}` : undefined' ) template(#actions) template(v-if='p.kind === "collecting"') diff --git a/components/desktop/src/pages/Marketplace/OffererSupplyPreparation/lib/ttn.ts b/components/desktop/src/pages/Marketplace/OffererSupplyPreparation/lib/ttn.ts index 60b0c1baf41..4c770607fdc 100644 --- a/components/desktop/src/pages/Marketplace/OffererSupplyPreparation/lib/ttn.ts +++ b/components/desktop/src/pages/Marketplace/OffererSupplyPreparation/lib/ttn.ts @@ -64,7 +64,7 @@ export function buildTtnData( const boxes = unitsPerBox && unitsPerBox > 0 ? Math.ceil(o.quantity / unitsPerBox) : undefined; return { sku: o.offer_id ? String(o.offer_id).slice(0, 8) : '—', - title: o.product_name, + title: o.product_name || 'Товар по предложению', qty: o.quantity, unit: marketplaceUnitShort(o.unit_of_measure), price: parseFloat(o.price_per_unit) || 0, diff --git a/components/desktop/src/pages/Marketplace/OnboardingMemberPickCpp/ui/OnboardingMemberPickCppPage.vue b/components/desktop/src/pages/Marketplace/OnboardingMemberPickCpp/ui/OnboardingMemberPickCppPage.vue index 82ce315095a..c91aa8820d3 100644 --- a/components/desktop/src/pages/Marketplace/OnboardingMemberPickCpp/ui/OnboardingMemberPickCppPage.vue +++ b/components/desktop/src/pages/Marketplace/OnboardingMemberPickCpp/ui/OnboardingMemberPickCppPage.vue @@ -230,8 +230,8 @@ q-page.mp-role-orderer.mp-member-cpp(role="region", aria-label="Подключе .mp-member-cpp__head-icon q-icon(name="location_on", size="22px") .mp-member-cpp__head-text - .text-subtitle1.text-weight-medium Выберите пункт выдачи - .text-body2.text-grey-7 Где будете забирать заказы. Каталог отфильтруется под выбранный участок. + .text-subtitle1.text-weight-medium Выберите пункт выдачи заказов + .text-body2.text-grey-7 Выбирайте участок, где вам удобно забирать заказы, — сменить его можно в любой момент. BaseChip.mp-member-cpp__picked(v-if="selectedName", variant="pos", size="sm") q-icon(name="check", size="14px") | {{ selectedName }} diff --git a/components/desktop/src/pages/Marketplace/OperatorBranchEconomy/ui/OperatorBranchEconomyPage.vue b/components/desktop/src/pages/Marketplace/OperatorBranchEconomy/ui/OperatorBranchEconomyPage.vue index c3a575ed5fb..ee0c3c6dc74 100644 --- a/components/desktop/src/pages/Marketplace/OperatorBranchEconomy/ui/OperatorBranchEconomyPage.vue +++ b/components/desktop/src/pages/Marketplace/OperatorBranchEconomy/ui/OperatorBranchEconomyPage.vue @@ -170,7 +170,7 @@ const planSaving = ref(false) function planDueLabel(plan: ExpensePlanView): string { if (plan.priority === Zeus.ExpensePlanPriority.URGENT) return 'Срочный' if (plan.priority === Zeus.ExpensePlanPriority.OPTIONAL) return 'Необязательный' - return plan.due_date ? new Date(plan.due_date).toLocaleDateString('ru-RU') : '—' + return plan.due_date ? new Date(String(plan.due_date)).toLocaleDateString('ru-RU') : '—' } async function onAddPlan(): Promise { diff --git a/components/desktop/src/pages/Marketplace/OperatorReception/ui/OperatorReceptionPage.vue b/components/desktop/src/pages/Marketplace/OperatorReception/ui/OperatorReceptionPage.vue index f1fe2a61c6f..cc8d008d31f 100644 --- a/components/desktop/src/pages/Marketplace/OperatorReception/ui/OperatorReceptionPage.vue +++ b/components/desktop/src/pages/Marketplace/OperatorReception/ui/OperatorReceptionPage.vue @@ -258,7 +258,7 @@ function aggregateLines(orders: MarketplaceSupplierPickupOrderView[]): DeliveryL map.set(key, { key, productName: o.product_name || 'Товар по предложению', - unit: o.unit_of_measure, + unit: o.unit_of_measure ?? '', quantity: qty, boxes, }); @@ -382,7 +382,7 @@ function groupOrdersByProduct(orders: MarketplaceSupplierPickupOrderView[]): Pic map.set(key, { key, productName: o.product_name || 'Товар по предложению', - unit: o.unit_of_measure, + unit: o.unit_of_measure ?? '', orderedTotal: qty, orders: [o], }); diff --git a/components/desktop/src/pages/Marketplace/OrdererConsolidated/ui/OrdererConsolidatedPage.vue b/components/desktop/src/pages/Marketplace/OrdererConsolidated/ui/OrdererConsolidatedPage.vue index 82de6100109..5a65cd2603c 100644 --- a/components/desktop/src/pages/Marketplace/OrdererConsolidated/ui/OrdererConsolidatedPage.vue +++ b/components/desktop/src/pages/Marketplace/OrdererConsolidated/ui/OrdererConsolidatedPage.vue @@ -88,6 +88,7 @@ interface CollectiveParty { orders: MarketplaceOrderView[]; /** Свой вклад (сумма собственных заказов в этой партии). */ ownUnits: number; + /** С учётом членского взноса (requirement b6) — то, что заказчик реально платит. */ ownCost: number; /** Накоплено всеми пайщиками (с бэкенда): пул сбора или объём партии. */ groupAccumulated: number | null; @@ -127,7 +128,7 @@ const parties = computed(() => { } p.orders.push(o); p.ownUnits += o.quantity; - p.ownCost += parseFloat(o.total_cost) || 0; + p.ownCost += Number(o.total_cost_with_fee); const candidate = STAGE_RANK[o.status]; const current = STAGE_RANK[p.stageStatus]; if (candidate < 90 && (current >= 90 || candidate < current)) { diff --git a/components/desktop/src/pages/Marketplace/OrdererOrderDetail/ui/OrdererOrderDetailPage.vue b/components/desktop/src/pages/Marketplace/OrdererOrderDetail/ui/OrdererOrderDetailPage.vue index 743f72d0753..8f2b0450ea5 100644 --- a/components/desktop/src/pages/Marketplace/OrdererOrderDetail/ui/OrdererOrderDetailPage.vue +++ b/components/desktop/src/pages/Marketplace/OrdererOrderDetail/ui/OrdererOrderDetailPage.vue @@ -46,6 +46,14 @@ const status = computed(() => (order.value ? orderStatusDisplay(order.value.stat const unitShort = computed(() => marketplaceUnitShort(order.value?.unit_of_measure)); const cancellable = computed(() => order.value?.status === 'ACTIVE'); +// requirement b6: заказчику показываем цену С членским взносом (как в +// каталоге) — order.total_cost_with_fee уже посчитан бэком (total_cost + +// membership_fee, зафиксированный контрактом по ставке на момент заказа). +const totalWithFee = computed(() => (order.value ? Number(order.value.total_cost_with_fee) : 0)); +const unitPriceWithFee = computed(() => + order.value && order.value.quantity > 0 ? totalWithFee.value / order.value.quantity : 0, +); + const pvzName = computed(() => order.value?.delivery_point_name || order.value?.delivery_braname || ''); const pvzAddress = computed(() => order.value?.delivery_point_address || ''); @@ -129,7 +137,7 @@ function confirmCancel(): void { if (!o) return; Dialog.create({ title: 'Отменить заказ?', - message: `Заказ № ${o.id.slice(0, 8)} (${o.quantity} ед., ${o.total_cost} ₽) будет отменён. Средства разблокируются на кошельке Стола заказов.`, + message: `Заказ № ${o.id.slice(0, 8)} (${o.quantity} ед., ${formatPrice(o.total_cost_with_fee)}) будет отменён. Средства разблокируются на кошельке Стола заказов.`, cancel: { label: 'Не отменять', flat: true }, ok: { label: 'Отменить заказ', color: 'negative', unelevated: true }, persistent: true, @@ -199,13 +207,13 @@ q-page.order-detail(role="region", aria-label="Заказ") .order-detail__facts .order-detail__fact .order-detail__fact-label Сумма заказа - .order-detail__fact-value--money {{ formatPrice(order.total_cost) }} + .order-detail__fact-value--money {{ formatPrice(String(totalWithFee)) }} .order-detail__fact .order-detail__fact-label Количество .order-detail__fact-value {{ order.quantity }} {{ unitShort }} .order-detail__fact .order-detail__fact-label Цена за единицу - .order-detail__fact-value {{ formatPrice(order.price_per_unit) }} + .order-detail__fact-value {{ formatPrice(String(unitPriceWithFee)) }} BaseCard.order-detail__card(v-if="pvzName || pvzAddress") template(#head) diff --git a/components/desktop/src/pages/Marketplace/SupplierRegistry/ui/SupplierRegistryPage.vue b/components/desktop/src/pages/Marketplace/SupplierRegistry/ui/SupplierRegistryPage.vue index bc6aad50a93..c0ecaf52eaf 100644 --- a/components/desktop/src/pages/Marketplace/SupplierRegistry/ui/SupplierRegistryPage.vue +++ b/components/desktop/src/pages/Marketplace/SupplierRegistry/ui/SupplierRegistryPage.vue @@ -1,5 +1,6 @@